diff --git a/.classpath b/.classpath index 1ef2da16..400c29d9 100644 --- a/.classpath +++ b/.classpath @@ -1,11 +1,11 @@ - - - - - - - - + + + + + + + + diff --git a/.project b/.project index 28fade93..b0af74e0 100644 --- a/.project +++ b/.project @@ -1,37 +1,37 @@ - pivot4j - - - - - - org.eclipse.wst.common.project.facet.core.builder - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.m2e.core.maven2Builder - - - - - org.eclipse.wst.validation.validationbuilder - - - - - - org.sonar.ide.eclipse.core.sonarNature - org.eclipse.jem.workbench.JavaEMFNature - org.eclipse.wst.common.modulecore.ModuleCoreNature - org.eclipse.jdt.core.javanature - org.eclipse.m2e.core.maven2Nature - org.eclipse.wst.common.project.facet.core.nature - + pivot4j + + + + + + org.eclipse.wst.common.project.facet.core.builder + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + org.eclipse.wst.validation.validationbuilder + + + + + + org.sonar.ide.eclipse.core.sonarNature + org.eclipse.jem.workbench.JavaEMFNature + org.eclipse.wst.common.modulecore.ModuleCoreNature + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + org.eclipse.wst.common.project.facet.core.nature + diff --git a/.settings/org.eclipse.wst.common.project.facet.core.xml b/.settings/org.eclipse.wst.common.project.facet.core.xml index c78d9323..bdf2e17e 100644 --- a/.settings/org.eclipse.wst.common.project.facet.core.xml +++ b/.settings/org.eclipse.wst.common.project.facet.core.xml @@ -1,5 +1,5 @@ - - + + diff --git a/README.md b/README.md index b103bcbf..eda53fa0 100644 --- a/README.md +++ b/README.md @@ -10,3 +10,5 @@ Project Page ======= Please visit Pivot4J home page at http://www.pivot4j.org + +ShowCase page http://scobr.com.br/pivot4j, User: admin Password: password diff --git a/pivot4j-analytics/${derby.home}/foodmart/db.lck b/pivot4j-analytics/${derby.home}/foodmart/db.lck new file mode 100644 index 00000000..51928e80 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/db.lck differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/dbex.lck b/pivot4j-analytics/${derby.home}/foodmart/dbex.lck new file mode 100644 index 00000000..720d64f4 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/dbex.lck differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/log/log.ctrl b/pivot4j-analytics/${derby.home}/foodmart/log/log.ctrl new file mode 100644 index 00000000..5bd2c078 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/log/log.ctrl differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/log/log51.dat b/pivot4j-analytics/${derby.home}/foodmart/log/log51.dat new file mode 100644 index 00000000..e99fcc3c Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/log/log51.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/log/logmirror.ctrl b/pivot4j-analytics/${derby.home}/foodmart/log/logmirror.ctrl new file mode 100644 index 00000000..5bd2c078 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/log/logmirror.ctrl differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c10.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c10.dat new file mode 100644 index 00000000..af257338 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c10.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c101.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c101.dat new file mode 100644 index 00000000..bad8078c Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c101.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c111.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c111.dat new file mode 100644 index 00000000..46f59be4 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c111.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c121.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c121.dat new file mode 100644 index 00000000..15205057 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c121.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c130.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c130.dat new file mode 100644 index 00000000..bab5d0c5 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c130.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c141.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c141.dat new file mode 100644 index 00000000..46d489ac Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c141.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c150.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c150.dat new file mode 100644 index 00000000..32f999f8 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c150.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c161.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c161.dat new file mode 100644 index 00000000..cd0f1321 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c161.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c171.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c171.dat new file mode 100644 index 00000000..fcb75320 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c171.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c180.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c180.dat new file mode 100644 index 00000000..acc058cd Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c180.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c191.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c191.dat new file mode 100644 index 00000000..b2d149a0 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c191.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c1a1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c1a1.dat new file mode 100644 index 00000000..4ea588cf Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c1a1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c1b1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c1b1.dat new file mode 100644 index 00000000..0dc2684e Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c1b1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c1c0.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c1c0.dat new file mode 100644 index 00000000..359525a3 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c1c0.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c1d1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c1d1.dat new file mode 100644 index 00000000..9f257df9 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c1d1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c1e0.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c1e0.dat new file mode 100644 index 00000000..e43e52fb Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c1e0.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c1f1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c1f1.dat new file mode 100644 index 00000000..7e6ee3b1 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c1f1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c20.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c20.dat new file mode 100644 index 00000000..d39c634f Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c20.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c200.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c200.dat new file mode 100644 index 00000000..cae919d0 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c200.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c211.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c211.dat new file mode 100644 index 00000000..c7e311b0 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c211.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c221.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c221.dat new file mode 100644 index 00000000..28e89367 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c221.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c230.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c230.dat new file mode 100644 index 00000000..69f48fb4 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c230.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c241.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c241.dat new file mode 100644 index 00000000..649ae139 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c241.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c251.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c251.dat new file mode 100644 index 00000000..d3d6adf4 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c251.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c260.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c260.dat new file mode 100644 index 00000000..8d7333df Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c260.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c271.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c271.dat new file mode 100644 index 00000000..af722f7d Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c271.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c281.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c281.dat new file mode 100644 index 00000000..3972983c Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c281.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c290.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c290.dat new file mode 100644 index 00000000..31577b81 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c290.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c2a1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c2a1.dat new file mode 100644 index 00000000..0f700d13 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c2a1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c2b1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c2b1.dat new file mode 100644 index 00000000..1d6382fb Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c2b1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c2c1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c2c1.dat new file mode 100644 index 00000000..3bc60d88 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c2c1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c2d0.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c2d0.dat new file mode 100644 index 00000000..d44eac03 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c2d0.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c2e1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c2e1.dat new file mode 100644 index 00000000..44e292d2 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c2e1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c2f0.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c2f0.dat new file mode 100644 index 00000000..eb26be59 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c2f0.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c300.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c300.dat new file mode 100644 index 00000000..4a0be661 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c300.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c31.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c31.dat new file mode 100644 index 00000000..5de6bb47 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c31.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c310.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c310.dat new file mode 100644 index 00000000..d17f23d9 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c310.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c320.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c320.dat new file mode 100644 index 00000000..089e25dc Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c320.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c330.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c330.dat new file mode 100644 index 00000000..017dcf78 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c330.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c340.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c340.dat new file mode 100644 index 00000000..6367cf5c Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c340.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c350.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c350.dat new file mode 100644 index 00000000..fd4feee5 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c350.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c360.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c360.dat new file mode 100644 index 00000000..3a9d44b8 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c360.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c370.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c370.dat new file mode 100644 index 00000000..19b2cecf Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c370.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c380.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c380.dat new file mode 100644 index 00000000..85daa29f Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c380.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c390.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c390.dat new file mode 100644 index 00000000..a66bb6b9 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c390.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c3a0.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c3a0.dat new file mode 100644 index 00000000..1d4c7326 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c3a0.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c3b0.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c3b0.dat new file mode 100644 index 00000000..6d34c8fb Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c3b0.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c3c0.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c3c0.dat new file mode 100644 index 00000000..da994ca8 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c3c0.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c3d0.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c3d0.dat new file mode 100644 index 00000000..3d64e65c Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c3d0.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c3e0.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c3e0.dat new file mode 100644 index 00000000..ad611f31 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c3e0.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c3f0.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c3f0.dat new file mode 100644 index 00000000..de74d32b Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c3f0.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c400.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c400.dat new file mode 100644 index 00000000..4294c8fb Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c400.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c41.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c41.dat new file mode 100644 index 00000000..a7adf71d Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c41.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c410.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c410.dat new file mode 100644 index 00000000..9964b571 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c410.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c420.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c420.dat new file mode 100644 index 00000000..7ff82997 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c420.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c430.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c430.dat new file mode 100644 index 00000000..051ec0bb Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c430.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c440.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c440.dat new file mode 100644 index 00000000..655aac26 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c440.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c450.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c450.dat new file mode 100644 index 00000000..cf452076 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c450.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c460.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c460.dat new file mode 100644 index 00000000..0ce9283c Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c460.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c470.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c470.dat new file mode 100644 index 00000000..0fe6b83f Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c470.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c480.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c480.dat new file mode 100644 index 00000000..3dc7073f Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c480.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c490.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c490.dat new file mode 100644 index 00000000..9a9c0796 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c490.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c4a0.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c4a0.dat new file mode 100644 index 00000000..bc23bec8 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c4a0.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c4b0.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c4b0.dat new file mode 100644 index 00000000..1c8398ec Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c4b0.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c4c0.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c4c0.dat new file mode 100644 index 00000000..214fbfa6 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c4c0.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c4d0.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c4d0.dat new file mode 100644 index 00000000..57820a60 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c4d0.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c4e0.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c4e0.dat new file mode 100644 index 00000000..dbef617a Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c4e0.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c4f0.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c4f0.dat new file mode 100644 index 00000000..d8b29673 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c4f0.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c500.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c500.dat new file mode 100644 index 00000000..28c41155 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c500.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c51.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c51.dat new file mode 100644 index 00000000..4e442323 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c51.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c510.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c510.dat new file mode 100644 index 00000000..8ae6a61e Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c510.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c520.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c520.dat new file mode 100644 index 00000000..717ce188 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c520.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c530.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c530.dat new file mode 100644 index 00000000..1e5aecfb Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c530.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c541.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c541.dat new file mode 100644 index 00000000..e78e6557 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c541.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c551.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c551.dat new file mode 100644 index 00000000..9c126557 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c551.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c561.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c561.dat new file mode 100644 index 00000000..97a78851 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c561.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c571.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c571.dat new file mode 100644 index 00000000..d38ce19b Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c571.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c581.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c581.dat new file mode 100644 index 00000000..a8eb57d0 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c581.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c591.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c591.dat new file mode 100644 index 00000000..0d1e5e79 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c591.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c5a1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c5a1.dat new file mode 100644 index 00000000..a23b8125 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c5a1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c5b1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c5b1.dat new file mode 100644 index 00000000..ef851eee Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c5b1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c5c1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c5c1.dat new file mode 100644 index 00000000..c6cdb01d Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c5c1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c5d1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c5d1.dat new file mode 100644 index 00000000..4af0d8c5 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c5d1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c5e1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c5e1.dat new file mode 100644 index 00000000..70f3f6eb Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c5e1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c5f1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c5f1.dat new file mode 100644 index 00000000..9e26a372 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c5f1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c60.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c60.dat new file mode 100644 index 00000000..85171395 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c60.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c601.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c601.dat new file mode 100644 index 00000000..1600c965 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c601.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c611.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c611.dat new file mode 100644 index 00000000..d898d197 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c611.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c621.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c621.dat new file mode 100644 index 00000000..05204992 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c621.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c631.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c631.dat new file mode 100644 index 00000000..cb6567be Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c631.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c641.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c641.dat new file mode 100644 index 00000000..8a3f87a8 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c641.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c651.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c651.dat new file mode 100644 index 00000000..ecf14bda Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c651.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c661.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c661.dat new file mode 100644 index 00000000..23a27186 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c661.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c671.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c671.dat new file mode 100644 index 00000000..89ea28e7 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c671.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c681.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c681.dat new file mode 100644 index 00000000..752b8edc Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c681.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c691.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c691.dat new file mode 100644 index 00000000..18665a9c Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c691.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c6a1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c6a1.dat new file mode 100644 index 00000000..f305a8e9 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c6a1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c6b1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c6b1.dat new file mode 100644 index 00000000..35e036ef Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c6b1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c6c1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c6c1.dat new file mode 100644 index 00000000..3c641fa5 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c6c1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c6d1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c6d1.dat new file mode 100644 index 00000000..99e12db5 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c6d1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c6e1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c6e1.dat new file mode 100644 index 00000000..7f73cac4 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c6e1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c6f1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c6f1.dat new file mode 100644 index 00000000..d4a26527 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c6f1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c701.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c701.dat new file mode 100644 index 00000000..98e7a904 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c701.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c71.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c71.dat new file mode 100644 index 00000000..9a5310a2 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c71.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c711.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c711.dat new file mode 100644 index 00000000..9f8a9610 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c711.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c721.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c721.dat new file mode 100644 index 00000000..0cec980e Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c721.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c731.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c731.dat new file mode 100644 index 00000000..a7c669d2 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c731.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c741.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c741.dat new file mode 100644 index 00000000..73b8bbfe Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c741.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c751.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c751.dat new file mode 100644 index 00000000..4d14acd4 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c751.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c761.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c761.dat new file mode 100644 index 00000000..1302b64d Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c761.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c771.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c771.dat new file mode 100644 index 00000000..2be000d9 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c771.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c781.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c781.dat new file mode 100644 index 00000000..fe2e30ce Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c781.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c791.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c791.dat new file mode 100644 index 00000000..a6db69bd Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c791.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c7a1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c7a1.dat new file mode 100644 index 00000000..941f93b9 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c7a1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c7b1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c7b1.dat new file mode 100644 index 00000000..c8f03fd1 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c7b1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c7c1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c7c1.dat new file mode 100644 index 00000000..ee9e7d79 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c7c1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c7d1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c7d1.dat new file mode 100644 index 00000000..58e61c17 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c7d1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c7e1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c7e1.dat new file mode 100644 index 00000000..776a0a52 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c7e1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c7f1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c7f1.dat new file mode 100644 index 00000000..56f30bf9 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c7f1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c801.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c801.dat new file mode 100644 index 00000000..a848d4aa Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c801.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c81.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c81.dat new file mode 100644 index 00000000..bbf642d1 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c81.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c811.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c811.dat new file mode 100644 index 00000000..7dd56708 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c811.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c821.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c821.dat new file mode 100644 index 00000000..7bada4b6 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c821.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c831.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c831.dat new file mode 100644 index 00000000..8b5549f9 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c831.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c841.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c841.dat new file mode 100644 index 00000000..2eae021e Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c841.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c851.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c851.dat new file mode 100644 index 00000000..cc5529aa Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c851.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c861.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c861.dat new file mode 100644 index 00000000..a1b95b20 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c861.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c871.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c871.dat new file mode 100644 index 00000000..3f587f74 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c871.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c881.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c881.dat new file mode 100644 index 00000000..365daefd Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c881.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c891.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c891.dat new file mode 100644 index 00000000..ed498856 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c891.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c8a1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c8a1.dat new file mode 100644 index 00000000..a845d2f5 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c8a1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c8b1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c8b1.dat new file mode 100644 index 00000000..8c006b97 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c8b1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c8c1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c8c1.dat new file mode 100644 index 00000000..4667cecc Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c8c1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c8d1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c8d1.dat new file mode 100644 index 00000000..101fc5e7 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c8d1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c8e1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c8e1.dat new file mode 100644 index 00000000..7e6eb86b Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c8e1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c8f1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c8f1.dat new file mode 100644 index 00000000..280c9686 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c8f1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c90.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c90.dat new file mode 100644 index 00000000..0bada6b6 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c90.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c901.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c901.dat new file mode 100644 index 00000000..a64ee180 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c901.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c911.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c911.dat new file mode 100644 index 00000000..2498a727 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c911.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c921.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c921.dat new file mode 100644 index 00000000..06481d8a Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c921.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c931.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c931.dat new file mode 100644 index 00000000..338d9f21 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c931.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c941.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c941.dat new file mode 100644 index 00000000..425ed6d4 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c941.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c951.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c951.dat new file mode 100644 index 00000000..99c421d5 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c951.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c961.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c961.dat new file mode 100644 index 00000000..4211063d Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c961.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c971.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c971.dat new file mode 100644 index 00000000..26ddbed7 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c971.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c981.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c981.dat new file mode 100644 index 00000000..acb29208 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c981.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c991.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c991.dat new file mode 100644 index 00000000..b2cbe64e Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c991.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c9a1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c9a1.dat new file mode 100644 index 00000000..20b679c5 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c9a1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c9b1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c9b1.dat new file mode 100644 index 00000000..1ce120fa Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c9b1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c9c1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c9c1.dat new file mode 100644 index 00000000..0b58e868 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c9c1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c9d1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c9d1.dat new file mode 100644 index 00000000..bb8398d6 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c9d1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c9e1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c9e1.dat new file mode 100644 index 00000000..eaef4902 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c9e1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/c9f1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/c9f1.dat new file mode 100644 index 00000000..71d54c52 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/c9f1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/ca01.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/ca01.dat new file mode 100644 index 00000000..92e5ea63 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/ca01.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/ca1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/ca1.dat new file mode 100644 index 00000000..3f1e14ba Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/ca1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/ca11.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/ca11.dat new file mode 100644 index 00000000..5f638c22 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/ca11.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/ca21.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/ca21.dat new file mode 100644 index 00000000..d0650d83 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/ca21.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/ca31.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/ca31.dat new file mode 100644 index 00000000..7dc3078f Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/ca31.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/ca41.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/ca41.dat new file mode 100644 index 00000000..701b6562 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/ca41.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/ca51.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/ca51.dat new file mode 100644 index 00000000..b886942f Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/ca51.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/ca61.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/ca61.dat new file mode 100644 index 00000000..85ec855e Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/ca61.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/ca71.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/ca71.dat new file mode 100644 index 00000000..f46271f1 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/ca71.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/ca81.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/ca81.dat new file mode 100644 index 00000000..6e5e1ef6 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/ca81.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/ca91.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/ca91.dat new file mode 100644 index 00000000..fc4b66ef Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/ca91.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/caa1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/caa1.dat new file mode 100644 index 00000000..dcac4b59 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/caa1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/cab1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/cab1.dat new file mode 100644 index 00000000..4d9bd77f Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/cab1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/cac1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/cac1.dat new file mode 100644 index 00000000..e4c22b31 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/cac1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/cad1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/cad1.dat new file mode 100644 index 00000000..72842f54 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/cad1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/cae1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/cae1.dat new file mode 100644 index 00000000..7f2be0a4 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/cae1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/caf1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/caf1.dat new file mode 100644 index 00000000..115c03dc Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/caf1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/cb01.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/cb01.dat new file mode 100644 index 00000000..3e87891e Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/cb01.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/cb1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/cb1.dat new file mode 100644 index 00000000..100f9ced Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/cb1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/cb11.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/cb11.dat new file mode 100644 index 00000000..cd9e1b8a Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/cb11.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/cb21.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/cb21.dat new file mode 100644 index 00000000..315445fd Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/cb21.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/cb31.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/cb31.dat new file mode 100644 index 00000000..22638f12 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/cb31.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/cc0.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/cc0.dat new file mode 100644 index 00000000..2ffc801f Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/cc0.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/cd1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/cd1.dat new file mode 100644 index 00000000..859128a7 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/cd1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/ce1.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/ce1.dat new file mode 100644 index 00000000..9114ecc6 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/ce1.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/cf0.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/cf0.dat new file mode 100644 index 00000000..91abb42d Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/cf0.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/db40.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/db40.dat new file mode 100644 index 00000000..3ae11739 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/db40.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/db50.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/db50.dat new file mode 100644 index 00000000..898f6a13 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/db50.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/db60.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/db60.dat new file mode 100644 index 00000000..898f6a13 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/db60.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/db70.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/db70.dat new file mode 100644 index 00000000..bcd2bd90 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/db70.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/db80.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/db80.dat new file mode 100644 index 00000000..3ae11739 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/db80.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/db90.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/db90.dat new file mode 100644 index 00000000..898f6a13 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/db90.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/dba0.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/dba0.dat new file mode 100644 index 00000000..898f6a13 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/dba0.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/dbb0.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/dbb0.dat new file mode 100644 index 00000000..bcd2bd90 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/dbb0.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/dbc0.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/dbc0.dat new file mode 100644 index 00000000..3ae11739 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/dbc0.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/dbd0.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/dbd0.dat new file mode 100644 index 00000000..898f6a13 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/dbd0.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/dbe0.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/dbe0.dat new file mode 100644 index 00000000..898f6a13 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/dbe0.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/dbf0.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/dbf0.dat new file mode 100644 index 00000000..bcd2bd90 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/dbf0.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/dc00.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/dc00.dat new file mode 100644 index 00000000..3ae11739 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/dc00.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/dc10.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/dc10.dat new file mode 100644 index 00000000..898f6a13 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/dc10.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/dc20.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/dc20.dat new file mode 100644 index 00000000..898f6a13 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/dc20.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/seg0/dc30.dat b/pivot4j-analytics/${derby.home}/foodmart/seg0/dc30.dat new file mode 100644 index 00000000..bcd2bd90 Binary files /dev/null and b/pivot4j-analytics/${derby.home}/foodmart/seg0/dc30.dat differ diff --git a/pivot4j-analytics/${derby.home}/foodmart/service.properties b/pivot4j-analytics/${derby.home}/foodmart/service.properties new file mode 100644 index 00000000..2cf59c4b --- /dev/null +++ b/pivot4j-analytics/${derby.home}/foodmart/service.properties @@ -0,0 +1,22 @@ +#C:\Derby\db-derby-10.1.2.1-bin\frameworks\NetworkServer\bin\foodmart +# ******************************************************************** +# *** Please do NOT edit this file. *** +# *** CHANGING THE CONTENT OF THIS FILE MAY CAUSE DATA CORRUPTION. *** +# ******************************************************************** +#Sun Mar 19 09:45:37 PST 2006 +SysschemasIndex2Identifier=225 +SyscolumnsIdentifier=144 +SysconglomeratesIndex1Identifier=49 +SysconglomeratesIdentifier=32 +SyscolumnsIndex2Identifier=177 +SysschemasIndex1Identifier=209 +SysconglomeratesIndex3Identifier=81 +SystablesIndex2Identifier=129 +SyscolumnsIndex1Identifier=161 +derby.serviceProtocol=org.apache.derby.database.Database +SysschemasIdentifier=192 +derby.storage.propertiesId=16 +SysconglomeratesIndex2Identifier=65 +derby.serviceLocale=en_US +SystablesIdentifier=96 +SystablesIndex1Identifier=113 diff --git a/pivot4j-analytics/.classpath b/pivot4j-analytics/.classpath index bf8c7965..c3b3b401 100644 --- a/pivot4j-analytics/.classpath +++ b/pivot4j-analytics/.classpath @@ -1,33 +1,33 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pivot4j-analytics/.project b/pivot4j-analytics/.project index 99912af2..2c763f0c 100644 --- a/pivot4j-analytics/.project +++ b/pivot4j-analytics/.project @@ -1,43 +1,43 @@ - pivot4j-analytics - - - - - - org.eclipse.wst.jsdt.core.javascriptValidator - - - - - org.eclipse.wst.common.project.facet.core.builder - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.wst.validation.validationbuilder - - - - - org.eclipse.m2e.core.maven2Builder - - - - - - org.sonar.ide.eclipse.core.sonarNature - org.eclipse.jem.workbench.JavaEMFNature - org.eclipse.wst.common.modulecore.ModuleCoreNature - org.eclipse.jdt.core.javanature - org.eclipse.m2e.core.maven2Nature - org.eclipse.wst.common.project.facet.core.nature - org.eclipse.wst.jsdt.core.jsNature - + pivot4j-analytics + + + + + + org.eclipse.wst.jsdt.core.javascriptValidator + + + + + org.eclipse.wst.common.project.facet.core.builder + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.wst.validation.validationbuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.sonar.ide.eclipse.core.sonarNature + org.eclipse.jem.workbench.JavaEMFNature + org.eclipse.wst.common.modulecore.ModuleCoreNature + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + org.eclipse.wst.common.project.facet.core.nature + org.eclipse.wst.jsdt.core.jsNature + diff --git a/pivot4j-analytics/.settings/.jsdtscope b/pivot4j-analytics/.settings/.jsdtscope index b46b9207..42d3bca7 100644 --- a/pivot4j-analytics/.settings/.jsdtscope +++ b/pivot4j-analytics/.settings/.jsdtscope @@ -1,12 +1,12 @@ - - - - - - - - - + + + + + + + + + diff --git a/pivot4j-analytics/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml b/pivot4j-analytics/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml index c32233e2..bea0e1d2 100644 --- a/pivot4j-analytics/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml +++ b/pivot4j-analytics/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml @@ -1,7 +1,7 @@ - - - - - + + + + + diff --git a/pivot4j-analytics/.settings/org.eclipse.wst.common.project.facet.core.xml b/pivot4j-analytics/.settings/org.eclipse.wst.common.project.facet.core.xml index 8c193b0d..a62ca085 100644 --- a/pivot4j-analytics/.settings/org.eclipse.wst.common.project.facet.core.xml +++ b/pivot4j-analytics/.settings/org.eclipse.wst.common.project.facet.core.xml @@ -1,8 +1,8 @@ - - - - - + + + + + diff --git a/pivot4j-analytics/faces-config.NavData b/pivot4j-analytics/faces-config.NavData new file mode 100644 index 00000000..187ec92e --- /dev/null +++ b/pivot4j-analytics/faces-config.NavData @@ -0,0 +1,6 @@ + + + + + + diff --git a/pivot4j-analytics/nb-configuration.xml b/pivot4j-analytics/nb-configuration.xml new file mode 100644 index 00000000..c14e6bd6 --- /dev/null +++ b/pivot4j-analytics/nb-configuration.xml @@ -0,0 +1,21 @@ + + + + + + WildFly + false + Facelets + true + + diff --git a/pivot4j-analytics/pom.xml b/pivot4j-analytics/pom.xml index 4ee75728..a1d23f98 100644 --- a/pivot4j-analytics/pom.xml +++ b/pivot4j-analytics/pom.xml @@ -1,578 +1,716 @@ - 4.0.0 - - org.pivot4j - pivot4j - 1.0-SNAPSHOT - ../pom.xml - + 4.0.0 + + org.pivot4j + pivot4j + 1.0-SNAPSHOT + ../pom.xml + - pivot4j-analytics - Pivot4J Analytics - Pivot4J Analytics is a sample application built with PrimeFaces to show basic usage of Pivot4J library. - war + pivot4j-analytics + Pivot4J Analytics + Pivot4J Analytics is a sample application built with PrimeFaces to show basic usage of Pivot4J library. + war - - Development - debug - info - 9090 - ${project.build.directory}/${project.artifactId}-${project.version}/WEB-INF - true - - - - - org.apache.maven.plugins - maven-antrun-plugin - ${version.plugin.antrun} - - - prepare-package - - - - - - - run - - - - - - maven-war-plugin - ${version.plugin.war} - - pivot4j - false - true - ${project.build.directory}/generated-resources/xml/xslt/web.xml - - - ${project.build.directory}/generated-resources/xml/xslt - - log4j-test.xml - mondrian.properties - - WEB-INF/classes - - - - - - org.apache.maven.plugins - maven-failsafe-plugin - ${version.plugin.failsafe} - - - - integration-test - verify - - - - ${browser.capabilities} - - ${skip.test} - - - - - - org.carlspring.maven - derby-maven-plugin - ${version.plugin.derby} - - - start-derby - pre-integration-test - - start - - - ${derby.home} - - - - stop-derby - post-integration-test - - stop - - - - - - org.jacoco - jacoco-maven-plugin - - - org.pivot4j.analytics.* - - - - - pre-test - - prepare-agent - - - - post-test - test - - report - - - - - - org.codehaus.mojo - xml-maven-plugin - ${version.plugin.xml} - - - prepare-package - - transform - - - - - - - ${basedir}/src/main/webapp/WEB-INF - - web.xml - - ${basedir}/src/main/xsl/web.xsl - - - jsf.project.stage - ${jsf.project.stage} - - - - - ${basedir}/src/main/resources/ - - log4j2-test.xml - - ${basedir}/src/main/xsl/log4j2-test.xsl - - - logger.level - ${logger.level} - - - root.level - ${root.logger.level} - - - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - ${version.plugin.javadoc} - - - javadoc-jar - package - - jar - - - - - - org.apache.maven.plugins - maven-source-plugin - ${version.plugin.source} - - - attach-sources - verify - - jar-no-fork - - - - - + + Production + error + info + 9090 + ${project.build.directory}/${project.artifactId}-${project.version}/WEB-INF + true + UTF-8 + + + + + org.apache.maven.plugins + maven-antrun-plugin + ${version.plugin.antrun} + + + prepare-package + + + + + + + run + + + + + + maven-war-plugin + ${version.plugin.war} + + pivot4j + false + true + ${project.build.directory}/generated-resources/xml/xslt/web.xml + + + ${project.build.directory}/generated-resources/xml/xslt + + log4j-test.xml + mondrian.properties + + WEB-INF/classes + + + ${basedir}/src/main/resources + + context.xml + + META-INF + + + + + + org.apache.maven.plugins + maven-failsafe-plugin + ${version.plugin.failsafe} + + + + integration-test + verify + + + + ${browser.capabilities} + + ${skip.test} + + + + + + org.carlspring.maven + derby-maven-plugin + ${version.plugin.derby} + + + start-derby + pre-integration-test + + start + + + ${derby.home} + + + + stop-derby + post-integration-test + + stop + + + + + + org.jacoco + jacoco-maven-plugin + + + org.pivot4j.analytics.* + + + + + pre-test + + prepare-agent + + + + post-test + test + + report + + + + + + org.codehaus.mojo + xml-maven-plugin + ${version.plugin.xml} + + + prepare-package + + transform + + + + + + + ${basedir}/src/main/webapp/WEB-INF + + web.xml + + ${basedir}/src/main/xsl/web.xsl + + + jsf.project.stage + ${jsf.project.stage} + + + + + ${basedir}/src/main/resources/ + + log4j2-test.xml + + ${basedir}/src/main/xsl/log4j2-test.xsl + + + logger.level + ${logger.level} + + + root.level + ${root.logger.level} + + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${version.plugin.javadoc} + + + javadoc-jar + package + + jar + + + + + + org.apache.maven.plugins + maven-source-plugin + ${version.plugin.source} + + + attach-sources + verify + + jar-no-fork + + + + + - - - ${basedir}/src/main/resources - - log4j-test.xml - mondrian.properties - - false - - - + + + ${basedir}/src/main/resources + + log4j-test.xml + + false + + + - - - org.pivot4j - pivot4j-core - ${project.version} - - - org.apache.logging.log4j - log4j-api - ${version.log4j} - - - org.apache.logging.log4j - log4j-core - ${version.log4j} - - - org.apache.logging.log4j - log4j-web - ${version.log4j} - - - org.apache.logging.log4j - log4j-slf4j-impl - ${version.log4j} - - - org.apache.logging.log4j - log4j-1.2-api - ${version.log4j} - - - org.apache.logging.log4j - log4j-jcl - ${version.log4j} - - - xerces - xercesImpl - ${version.xerces} - runtime - - - org.olap4j - olap4j-xmla - ${version.olap4j} - - - commons-dbutils - commons-dbutils - ${version.commons.dbutils} - - - javax.servlet - servlet-api - ${version.servlet} - provided - - - javax.servlet.jsp - jsp-api - ${version.jsp} - provided - - - javax.el - javax.el-api - ${version.el} - provided - - - javax.servlet - jstl - ${version.jstl} - - - org.primefaces - primefaces - ${version.primefaces} - - - org.primefaces.extensions - primefaces-extensions - ${version.primefaces.extensions} - - - org.primefaces.extensions - resources-codemirror - ${version.primefaces.extensions} - - - org.primefaces.themes - black-tie - ${version.primefaces.themes} - - - org.primefaces.themes - bootstrap - ${version.primefaces.themes} - - - org.primefaces.themes - cruze - ${version.primefaces.themes} - - - org.primefaces.themes - humanity - ${version.primefaces.themes} - - - org.primefaces.themes - redmond - ${version.primefaces.themes} - - - org.primefaces.themes - rocket - ${version.primefaces.themes} - - - org.apache.derby - derby - ${version.derby} - - - org.apache.derby - derbyclient - ${version.derby} - test - - - pentaho - mondrian - ${version.mondrian} - - - javax.servlet - jsp-api - - - javacup - javacup - - - log4j - log4j - - - - - org.jboss.shrinkwrap.resolver - shrinkwrap-resolver-depchain - test - pom - - - org.jboss.arquillian.junit - arquillian-junit-container - test - - - org.jboss.arquillian.graphene - graphene-webdriver - pom - test - ${version.arquillian.graphene} - - - org.apache.httpcomponents - httpcore - test - ${version.httpclient} - - - org.seleniumhq.selenium - selenium-java - test - ${version.selenium} - - - org.seleniumhq.selenium - selenium-firefox-driver - test - ${version.selenium} - - - org.seleniumhq.selenium - selenium-chrome-driver - test - ${version.selenium} - - - org.seleniumhq.selenium - selenium-ie-driver - test - ${version.selenium} - - - org.seleniumhq.selenium - selenium-htmlunit-driver - test - ${version.selenium} - - - org.seleniumhq.selenium - selenium-remote-driver - test - ${version.selenium} - - - org.jboss.arquillian.extension - arquillian-drone-webdriver-depchain - pom - test - - - org.jboss.arquillian.extension - arquillian-jacoco - test - ${version.arquillian.jacoco} - - - org.jacoco - org.jacoco.core - test - ${version.jacoco} - - + + + org.pivot4j + pivot4j-core + ${project.version} + + + org.apache.logging.log4j + log4j-api + ${version.log4j} + + + org.apache.logging.log4j + log4j-core + ${version.log4j} + + + org.apache.logging.log4j + log4j-web + ${version.log4j} + + + org.apache.logging.log4j + log4j-slf4j-impl + ${version.log4j} + + + org.apache.logging.log4j + log4j-1.2-api + ${version.log4j} + + + org.apache.logging.log4j + log4j-jcl + ${version.log4j} + + + xerces + xercesImpl + ${version.xerces} + runtime + + + org.olap4j + olap4j-xmla + ${version.olap4j} + + + commons-dbutils + commons-dbutils + ${version.commons.dbutils} + + + javax.servlet + servlet-api + ${version.servlet} + provided + + + javax.servlet.jsp + jsp-api + ${version.jsp} + provided + + + javax.el + javax.el-api + ${version.el} + provided + + + javax.servlet + jstl + ${version.jstl} + + + taglibs + standard + 1.1.2 + + + org.primefaces + primefaces + ${version.primefaces} + + + org.primefaces.extensions + primefaces-extensions + ${version.primefaces.extensions} + + + org.primefaces.extensions + resources-codemirror + ${version.primefaces.resources-codemirror} + + + org.primefaces.themes + black-tie + ${version.primefaces.themes} + + + org.primefaces.themes + bootstrap + ${version.primefaces.themes} + + + org.primefaces.themes + cruze + ${version.primefaces.themes} + + + org.primefaces.themes + humanity + ${version.primefaces.themes} + + + org.primefaces.themes + redmond + ${version.primefaces.themes} + + + org.primefaces.themes + rocket + ${version.primefaces.themes} + + + org.apache.derby + derby + ${version.derby} + + + org.apache.derby + derbyclient + ${version.derby} + test + + + pentaho + mondrian + ${version.mondrian} + + + javax.servlet + jsp-api + + + javacup + javacup + + + log4j + log4j + + + + + org.jboss.shrinkwrap.resolver + shrinkwrap-resolver-depchain + test + pom + + + org.jboss.arquillian.junit + arquillian-junit-container + test + + + org.jboss.arquillian.graphene + graphene-webdriver + pom + test + ${version.arquillian.graphene} + + + org.apache.httpcomponents + httpcore + test + ${version.httpclient} + + + org.seleniumhq.selenium + selenium-java + test + ${version.selenium} + + + org.seleniumhq.selenium + selenium-firefox-driver + test + ${version.selenium} + + + org.seleniumhq.selenium + selenium-chrome-driver + test + ${version.selenium} + + + org.seleniumhq.selenium + selenium-ie-driver + test + ${version.selenium} + + + org.seleniumhq.selenium + selenium-htmlunit-driver + test + ${version.selenium} + + + org.seleniumhq.selenium + selenium-remote-driver + test + ${version.selenium} + + + org.jboss.arquillian.extension + arquillian-drone-webdriver-depchain + pom + test + + + org.jboss.arquillian.extension + arquillian-jacoco + test + ${version.arquillian.jacoco} + + + com.fasterxml.uuid + java-uuid-generator + ${version.java.uuid.generator} + + + org.jacoco + org.jacoco.core + test + ${version.jacoco} + + + mysql + mysql-connector-java + ${version.mysql} + + + + + org.mariadb.jdbc + mariadb-java-client + ${version.mariadb} + - - - - org.jboss.shrinkwrap.resolver - shrinkwrap-resolver-bom - ${version.shrinkwrap} - import - pom - - - org.jboss.arquillian.extension - arquillian-drone-bom - ${version.arquillian.drone} - pom - import - - - org.jboss.arquillian - arquillian-bom - ${version.arquillian.bom} - import - pom - - - - - - prime-repo - PrimeFaces Maven Repository - http://repository.primefaces.org - default - - + + com.github.adminfaces + admin-theme + ${version.admin-theme} + + + + + org.postgresql + postgresql + ${version.postgresql} + + + org.apache.drill.exec + drill-jdbc-all + ${version.apache.drill} + - - - mojarra - - - org.glassfish - javax.faces - ${version.mojarra} - - - + + org.omnifaces + omnifaces + ${version.omnifaces} + + + + oracle + ojdbc6 + ${version.oracle} + + + + org.apache.poi + poi + ${version.poi} + + + org.apache.poi + poi-ooxml + ${version.poi} + - - myfaces - - true - - arquillian.test - true - - - - - org.apache.myfaces.core - myfaces-api - ${version.myfaces} - - - org.apache.myfaces.core - myfaces-impl - ${version.myfaces} - - - + + javax.inject + javax.inject + 1 + + + + + org.springframework + spring-webmvc + + + + org.springframework + spring-orm + - - tomcat6 - - true - - arquillian.test - true - - - - - org.jboss.arquillian.container - arquillian-tomcat-embedded-6 - ${version.arquillian.tomcat6} - test - - - org.apache.tomcat - catalina - ${version.tomcat6} - test - - - org.apache.tomcat - coyote - ${version.tomcat6} - provided - - - org.apache.tomcat - jasper - ${version.tomcat6} - provided - - - + + org.springframework.data + spring-data-jpa + ${version.springframework.data} + - - firefox - - firefox - false - - - - internetExplorer - - internetExplorer - false - - - - chrome - - chrome - false - - - + + org.springframework.security + spring-security-web + ${version.springframework.security} + + + + org.springframework.security + spring-security-config + ${version.springframework.security} + + + + org.springframework.boot + spring-boot-starter-thymeleaf + ${version.springframework.boot} + + + + org.springframework + spring-webflux + + + + org.jboss + jandex + 2.0.5.Final + runtime + + + + net.bootsfaces + bootsfaces + 1.4.0 + compile + + + + + + + + org.jboss.shrinkwrap.resolver + shrinkwrap-resolver-bom + ${version.shrinkwrap} + import + pom + + + org.jboss.arquillian.extension + arquillian-drone-bom + ${version.arquillian.drone} + pom + import + + + org.jboss.arquillian + arquillian-bom + ${version.arquillian.bom} + import + pom + + + + org.springframework + spring-framework-bom + 5.1.0.RELEASE + pom + import + + + + + + + + mojarra + + + org.glassfish + javax.faces + ${version.mojarra} + + + org.jboss.weld.servlet + weld-servlet-shaded + 3.0.3.Final + runtime + + + + + + myfaces + + true + + arquillian.test + true + + + + + org.apache.myfaces.core + myfaces-api + ${version.myfaces} + + + org.apache.myfaces.core + myfaces-impl + ${version.myfaces} + + + + + + tomcat6 + + true + + arquillian.test + true + + + + + org.jboss.arquillian.container + arquillian-tomcat-embedded-6 + ${version.arquillian.tomcat6} + test + + + org.apache.tomcat + catalina + ${version.tomcat6} + test + + + org.apache.tomcat + coyote + ${version.tomcat6} + provided + + + org.apache.tomcat + jasper + ${version.tomcat6} + provided + + + + + + firefox + + firefox + false + + + + internetExplorer + + internetExplorer + false + + + + chrome + + chrome + false + + + diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/AjaxColorPicker.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/AjaxColorPicker.java index c0007b34..f47c594c 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/AjaxColorPicker.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/AjaxColorPicker.java @@ -28,64 +28,66 @@ * component. */ @FacesComponent("org.pivot4j.component.ColorPicker") -@ResourceDependencies({ @ResourceDependency(library = "pivot4j", name = "js/colorpicker.js") }) +@ResourceDependencies({ + @ResourceDependency(library = "pivot4j", name = "js/colorpicker.js")}) public class AjaxColorPicker extends ColorPicker implements - ClientBehaviorHolder { + ClientBehaviorHolder { - public static final String COMPONENT_FAMILY = "org.pivot4j.component"; + public static final String COMPONENT_FAMILY = "org.pivot4j.component"; - public static final String COMPONENT_TYPE = "org.pivot4j.component.ColorPicker"; + public static final String COMPONENT_TYPE = "org.pivot4j.component.ColorPicker"; - public static final String RENDERER_TYPE = "org.pivot4j.component.ColorPickerRenderer"; + public static final String RENDERER_TYPE = "org.pivot4j.component.ColorPickerRenderer"; - public AjaxColorPicker() { - setRendererType(RENDERER_TYPE); - } + public AjaxColorPicker() { + setRendererType(RENDERER_TYPE); + } - /** - * @see org.primefaces.component.colorpicker.ColorPicker#getFamily() - */ - @Override - public String getFamily() { - return COMPONENT_FAMILY; - } + /** + * @see org.primefaces.component.colorpicker.ColorPicker#getFamily() + */ + @Override + public String getFamily() { + return COMPONENT_FAMILY; + } - /** - * @see javax.faces.component.UIComponentBase#getEventNames() - */ - @Override - public Collection getEventNames() { - return Arrays.asList("change"); - } + /** + * @see javax.faces.component.UIComponentBase#getEventNames() + */ + @Override + public Collection getEventNames() { + return Arrays.asList("change"); + } - /** - * @see javax.faces.component.UIComponentBase#queueEvent(javax.faces.event.FacesEvent) - */ - @Override - public void queueEvent(FacesEvent event) { - FacesContext context = getFacesContext(); + /** + * @see + * javax.faces.component.UIComponentBase#queueEvent(javax.faces.event.FacesEvent) + */ + @Override + public void queueEvent(FacesEvent event) { + FacesContext context = getFacesContext(); - if (event instanceof AjaxBehaviorEvent) { - AjaxBehaviorEvent behaviorEvent = (AjaxBehaviorEvent) event; - Map params = context.getExternalContext() - .getRequestParameterMap(); - String eventName = params - .get(Constants.RequestParams.PARTIAL_BEHAVIOR_EVENT_PARAM); - String clientId = this.getClientId(context); + if (event instanceof AjaxBehaviorEvent) { + AjaxBehaviorEvent behaviorEvent = (AjaxBehaviorEvent) event; + Map params = context.getExternalContext() + .getRequestParameterMap(); + String eventName = params + .get(Constants.RequestParams.PARTIAL_BEHAVIOR_EVENT_PARAM); + String clientId = this.getClientId(context); - if (eventName.equals("change")) { - String value = params.get(clientId + "_input"); + if (eventName.equals("change")) { + String value = params.get(clientId + "_input"); - if (value != null) { - ChangeEvent changeEvent = new ChangeEvent(this, - behaviorEvent.getBehavior(), value); - changeEvent.setPhaseId(behaviorEvent.getPhaseId()); + if (value != null) { + ChangeEvent changeEvent = new ChangeEvent(this, + behaviorEvent.getBehavior(), value); + changeEvent.setPhaseId(behaviorEvent.getPhaseId()); - super.queueEvent(changeEvent); - } - } - } else { - super.queueEvent(event); - } - } + super.queueEvent(changeEvent); + } + } + } else { + super.queueEvent(event); + } + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/AjaxColorPickerRenderer.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/AjaxColorPickerRenderer.java index 66228f29..919c8783 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/AjaxColorPickerRenderer.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/AjaxColorPickerRenderer.java @@ -22,36 +22,38 @@ @FacesRenderer(componentFamily = "org.pivot4j.component", rendererType = "org.pivot4j.component.ColorPickerRenderer") public class AjaxColorPickerRenderer extends ColorPickerRenderer { - public static final String RENDERER_TYPE = "org.pivot4j.component.ColorPickerRenderer"; - - /** - * @see org.primefaces.component.colorpicker.ColorPickerRenderer#decode(javax.faces.context.FacesContext, - * javax.faces.component.UIComponent) - */ - @Override - public void decode(FacesContext context, UIComponent component) { - decodeBehaviors(context, component); - - super.decode(context, component); - } - - /** - * @see org.primefaces.component.colorpicker.ColorPickerRenderer#encodeScript(javax.faces.context.FacesContext, - * org.primefaces.component.colorpicker.ColorPicker, java.lang.String) - */ - @Override - protected void encodeScript(FacesContext context, ColorPicker colorPicker, String value) - throws IOException { - String clientId = colorPicker.getClientId(context); - - WidgetBuilder wb = getWidgetBuilder(context); - - wb.init("AjaxColorPicker", colorPicker.resolveWidgetVar(), clientId, - "colorpicker").attr("mode", colorPicker.getMode()) - .attr("color", value, null); - - encodeClientBehaviors(context, (ClientBehaviorHolder) colorPicker); - - wb.finish(); - } + public static final String RENDERER_TYPE = "org.pivot4j.component.ColorPickerRenderer"; + + /** + * @see + * org.primefaces.component.colorpicker.ColorPickerRenderer#decode(javax.faces.context.FacesContext, + * javax.faces.component.UIComponent) + */ + @Override + public void decode(FacesContext context, UIComponent component) { + decodeBehaviors(context, component); + + super.decode(context, component); + } + + /** + * @see + * org.primefaces.component.colorpicker.ColorPickerRenderer#encodeScript(javax.faces.context.FacesContext, + * org.primefaces.component.colorpicker.ColorPicker, java.lang.String) + */ + @Override + protected void encodeScript(FacesContext context, ColorPicker colorPicker, String value) + throws IOException { + String clientId = colorPicker.getClientId(context); + + WidgetBuilder wb = getWidgetBuilder(context); + + wb.initWithComponentLoad("AjaxColorPicker", colorPicker.resolveWidgetVar(), clientId, + "colorpicker").attr("mode", colorPicker.getMode()) + .attr("color", value, null); + + encodeClientBehaviors(context, (ClientBehaviorHolder) colorPicker); + + wb.finish(); + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/ChangeEvent.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/ChangeEvent.java index 6016f380..e10606cf 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/ChangeEvent.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/ChangeEvent.java @@ -8,40 +8,42 @@ public class ChangeEvent extends AjaxBehaviorEvent { - private static final long serialVersionUID = -1474206753996627009L; - - private Object object; - - /** - * @param component - * @param behavior - * @param object - */ - public ChangeEvent(UIComponent component, Behavior behavior, Object object) { - super(component, behavior); - this.object = object; - } - - /** - * @see javax.faces.event.AjaxBehaviorEvent#isAppropriateListener(javax.faces.event.FacesListener) - */ - @Override - public boolean isAppropriateListener(FacesListener faceslistener) { - return (faceslistener instanceof AjaxBehaviorListener); - } - - /** - * @see javax.faces.event.AjaxBehaviorEvent#processListener(javax.faces.event.FacesListener) - */ - @Override - public void processListener(FacesListener faceslistener) { - ((AjaxBehaviorListener) faceslistener).processAjaxBehavior(this); - } - - /** - * @return - */ - public Object getObject() { - return object; - } -} \ No newline at end of file + private static final long serialVersionUID = -1474206753996627009L; + + private Object object; + + /** + * @param component + * @param behavior + * @param object + */ + public ChangeEvent(UIComponent component, Behavior behavior, Object object) { + super(component, behavior); + this.object = object; + } + + /** + * @see + * javax.faces.event.AjaxBehaviorEvent#isAppropriateListener(javax.faces.event.FacesListener) + */ + @Override + public boolean isAppropriateListener(FacesListener faceslistener) { + return (faceslistener instanceof AjaxBehaviorListener); + } + + /** + * @see + * javax.faces.event.AjaxBehaviorEvent#processListener(javax.faces.event.FacesListener) + */ + @Override + public void processListener(FacesListener faceslistener) { + ((AjaxBehaviorListener) faceslistener).processAjaxBehavior(this); + } + + /** + * @return + */ + public Object getObject() { + return object; + } +} diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/tree/AbstractTreeNode.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/tree/AbstractTreeNode.java index 2a1230e5..f33ca353 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/tree/AbstractTreeNode.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/tree/AbstractTreeNode.java @@ -9,151 +9,150 @@ public abstract class AbstractTreeNode implements TreeNode { - private static final String ROOT_ROW_KEY = "root"; - - private TreeNode parent; - - private boolean expanded = false; - - private boolean selectable = false; - - private boolean selected = false; - - private boolean partialSelected = false; - - /** - * @see org.primefaces.model.TreeNode#getParent() - */ - @Override - public TreeNode getParent() { - return parent; - } - - /** - * @see org.primefaces.model.TreeNode#setParent(org.primefaces.model.TreeNode) - */ - @Override - public void setParent(TreeNode parent) { - this.parent = parent; - } - - @Override - public void clearParent() { - this.parent = null; - } - - /** - * @see org.primefaces.model.TreeNode#isExpanded() - */ - @Override - public boolean isExpanded() { - return expanded; - } - - /** - * @see org.primefaces.model.TreeNode#setExpanded(boolean) - */ - @Override - public void setExpanded(boolean expanded) { - this.expanded = expanded; - } - - /** - * @see org.primefaces.model.TreeNode#isSelectable() - */ - @Override - public boolean isSelectable() { - return selectable; - } - - /** - * @see org.primefaces.model.TreeNode#setSelectable(boolean) - */ - @Override - public void setSelectable(boolean selectable) { - this.selectable = selectable; - } - - /** - * @see org.primefaces.model.TreeNode#isSelected() - */ - @Override - public boolean isSelected() { - return selected; - } - - /** - * @see org.primefaces.model.TreeNode#setSelected(boolean) - */ - @Override - public void setSelected(boolean selected) { - this.selected = selected; - } - - /** - * @return the rowKey - */ - public String getRowKey() { - if (getParent() == null) { - return ROOT_ROW_KEY; - } - - int index = getParent().getChildren().indexOf(this); - - String parentKey = getParent().getRowKey(); - - if (parentKey == null || parentKey.equals(ROOT_ROW_KEY)) { - return Integer.toString(index); - } - - return parentKey + "_" + index; - } - - /** - * @param rowKey - * the rowKey to set - */ - public void setRowKey(String rowKey) { - // No-op. - } - - /** - * @return the partialSelected - */ - public boolean isPartialSelected() { - return partialSelected; - } - - /** - * @param partialSelected - * the partialSelected to set - */ - public void setPartialSelected(boolean partialSelected) { - this.partialSelected = partialSelected; - } - - public List collectNodes(NodeCollector collector) { - if (collector == null) { - throw new NullArgumentException("collector"); - } - - List nodes = new LinkedList(); - - collectNodes(collector, this, nodes); - - return nodes; - } - - protected void collectNodes(NodeCollector collector, TreeNode node, - List nodes) { - if (collector.collectNode(node)) { - nodes.add(node); - } - - if (collector.searchNode(node) && !node.isLeaf()) { - for (TreeNode child : node.getChildren()) { - collectNodes(collector, child, nodes); - } - } - } + private static final String ROOT_ROW_KEY = "root"; + + private TreeNode parent; + + private boolean expanded = false; + + private boolean selectable = false; + + private boolean selected = false; + + private boolean partialSelected = false; + + /** + * @see org.primefaces.model.TreeNode#getParent() + */ + @Override + public TreeNode getParent() { + return parent; + } + + /** + * @see + * org.primefaces.model.TreeNode#setParent(org.primefaces.model.TreeNode) + */ + @Override + public void setParent(TreeNode parent) { + this.parent = parent; + } + + @Override + public void clearParent() { + this.parent = null; + } + + /** + * @see org.primefaces.model.TreeNode#isExpanded() + */ + @Override + public boolean isExpanded() { + return expanded; + } + + /** + * @see org.primefaces.model.TreeNode#setExpanded(boolean) + */ + @Override + public void setExpanded(boolean expanded) { + this.expanded = expanded; + } + + /** + * @see org.primefaces.model.TreeNode#isSelectable() + */ + @Override + public boolean isSelectable() { + return selectable; + } + + /** + * @see org.primefaces.model.TreeNode#setSelectable(boolean) + */ + @Override + public void setSelectable(boolean selectable) { + this.selectable = selectable; + } + + /** + * @see org.primefaces.model.TreeNode#isSelected() + */ + @Override + public boolean isSelected() { + return selected; + } + + /** + * @see org.primefaces.model.TreeNode#setSelected(boolean) + */ + @Override + public void setSelected(boolean selected) { + this.selected = selected; + } + + /** + * @return the rowKey + */ + public String getRowKey() { + if (getParent() == null) { + return ROOT_ROW_KEY; + } + + int index = getParent().getChildren().indexOf(this); + + String parentKey = getParent().getRowKey(); + + if (parentKey == null || parentKey.equals(ROOT_ROW_KEY)) { + return Integer.toString(index); + } + + return parentKey + "_" + index; + } + + /** + * @param rowKey the rowKey to set + */ + public void setRowKey(String rowKey) { + // No-op. + } + + /** + * @return the partialSelected + */ + public boolean isPartialSelected() { + return partialSelected; + } + + /** + * @param partialSelected the partialSelected to set + */ + public void setPartialSelected(boolean partialSelected) { + this.partialSelected = partialSelected; + } + + public List collectNodes(NodeCollector collector) { + if (collector == null) { + throw new NullArgumentException("collector"); + } + + List nodes = new LinkedList(); + + collectNodes(collector, this, nodes); + + return nodes; + } + + protected void collectNodes(NodeCollector collector, TreeNode node, + List nodes) { + if (collector.collectNode(node)) { + nodes.add(node); + } + + if (collector.searchNode(node) && !node.isLeaf()) { + for (TreeNode child : node.getChildren()) { + collectNodes(collector, child, nodes); + } + } + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/tree/DefaultTreeNode.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/tree/DefaultTreeNode.java index 168e3b73..4d54c4bf 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/tree/DefaultTreeNode.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/tree/DefaultTreeNode.java @@ -17,356 +17,356 @@ */ public class DefaultTreeNode extends AbstractTreeNode { - public static final String DEFAULT_TYPE = "default"; - - private String type; - - private Object data; - - private List children; - - public DefaultTreeNode() { - this(null); - } - - /** - * @param data - */ - public DefaultTreeNode(Object data) { - this.type = DEFAULT_TYPE; - this.children = new LazyTreeNodeChildren(this); - this.data = data; - } - - /** - * @param data - * @param parent - */ - public DefaultTreeNode(Object data, TreeNode parent) { - this.type = DEFAULT_TYPE; - this.data = data; - this.children = new LazyTreeNodeChildren(this); - - if (parent != null) { - parent.getChildren().add(this); - } - } - - /** - * @param type - * @param data - * @param parent - */ - public DefaultTreeNode(String type, Object data, TreeNode parent) { - this.type = type; - this.data = data; - this.children = new LazyTreeNodeChildren(this); - if (parent != null) { - parent.getChildren().add(this); - } - } - - /** - * @see org.primefaces.model.TreeNode#getType() - */ - @Override - public String getType() { - return type; - } - - /** - * @param type - */ - public void setType(String type) { - this.type = type; - } - - /** - * @see org.primefaces.model.TreeNode#getData() - */ - @Override - public Object getData() { - return data; - } - - /** - * @param data - */ - public void setData(Object data) { - this.data = data; - } - - /** - * @see org.primefaces.model.TreeNode#getChildren() - */ - @Override - public List getChildren() { - return children; - } - - /** - * @param children - */ - public void setChildren(List children) { - this.children = children; - } - - /** - * @see org.primefaces.model.TreeNode#getChildCount() - */ - @Override - public int getChildCount() { - return children.size(); - } - - /** - * @see org.primefaces.model.TreeNode#isLeaf() - */ - @Override - public boolean isLeaf() { - return CollectionUtils.isEmpty(children); - } - - /** - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - return new HashCodeBuilder().append(data).toHashCode(); - } - - /** - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } else if (obj == null) { - return false; - } - - if (!(obj instanceof DefaultTreeNode)) { - return false; - } - - DefaultTreeNode other = (DefaultTreeNode) obj; - - return ObjectUtils.equals(data, other.data); - } - - /** - * @see java.lang.Object#toString() - */ - @Override - public String toString() { - if (data != null) { - return data.toString(); - } else { - return super.toString(); - } - } - - static class LazyTreeNodeChildren extends ArrayList { - - private static final long serialVersionUID = 1L; - - private TreeNode parent; - - /** - * @param parent - */ - public LazyTreeNodeChildren(TreeNode parent) { - this.parent = parent; - } - - /** - * @param node - */ - private void eraseParent(TreeNode node) { - TreeNode parentNode = node.getParent(); - - if (parentNode != null) { - parentNode.getChildren().remove(node); - node.setParent(null); - } - } - - /** - * @see java.util.ArrayList#add(java.lang.Object) - */ - @Override - public boolean add(TreeNode node) { - if (node == null) { - throw new NullArgumentException("node"); - } - - eraseParent(node); - boolean result = super.add(node); - node.setParent(parent); - updateRowKeys(parent); - return result; - } - - /** - * @see java.util.ArrayList#add(int, java.lang.Object) - */ - @Override - public void add(int index, TreeNode node) { - if (node == null) { - throw new NullArgumentException("node"); - } - - if ((index < 0) || (index > size())) { - throw new IndexOutOfBoundsException(); - } - - eraseParent(node); - super.add(index, node); - node.setParent(parent); - updateRowKeys(parent); - } - - /** - * @see java.util.ArrayList#addAll(java.util.Collection) - */ - @Override - public boolean addAll(Collection collection) { - Iterator elements = (new ArrayList(collection)) - .iterator(); - - boolean changed = false; - while (elements.hasNext()) { - TreeNode node = elements.next(); - - eraseParent(node); - super.add(node); - node.setParent(parent); - changed = true; - } - - if (changed) { - updateRowKeys(parent); - } - - return (changed); - } - - /** - * @see java.util.ArrayList#addAll(int, java.util.Collection) - */ - @Override - public boolean addAll(int index, - Collection collection) { - Iterator elements = (new ArrayList(collection)) - .iterator(); - boolean changed = false; - while (elements.hasNext()) { - TreeNode node = elements.next(); - if (node == null) { - throw new NullPointerException(); - } else { - eraseParent(node); - super.add(index++, node); - node.setParent(parent); - changed = true; - } - } - - if (changed) { - updateRowKeys(parent); - } - - return (changed); - } - - /** - * @see java.util.ArrayList#set(int, java.lang.Object) - */ - @Override - public TreeNode set(int index, TreeNode node) { - if (node == null) { - throw new NullArgumentException("node"); - } - - if ((index < 0) || (index >= size())) { - throw new IndexOutOfBoundsException(); - } - - eraseParent(node); - TreeNode previous = get(index); - super.set(index, node); - previous.setParent(null); - node.setParent(parent); - updateRowKeys(parent); - - return previous; - } - - /** - * @see java.util.ArrayList#remove(int) - */ - @Override - public TreeNode remove(int index) { - TreeNode node = get(index); - node.setParent(null); - super.remove(index); - updateRowKeys(parent); - - return node; - } - - /** - * @see java.util.ArrayList#remove(java.lang.Object) - */ - @Override - public boolean remove(Object object) { - TreeNode node = (TreeNode) object; - if (node == null) { - throw new NullPointerException(); - } - - if (super.indexOf(node) != -1) { - node.setParent(null); - } - - if (super.remove(node)) { - updateRowKeys(parent); - return true; - } else { - return false; - } - } - - /** - * @param node - */ - private void updateRowKeys(TreeNode node) { - if (!node.isExpanded()) { - return; - } - - int count = node.getChildCount(); - - List children = node.getChildren(); - - for (int i = 0; i < count; i++) { - TreeNode childNode = children.get(i); - - String rowKey; - - if (node.getParent() == null) { - rowKey = String.valueOf(i); - } else { - rowKey = node.getRowKey() + "_" + i; - } - - childNode.setRowKey(rowKey); - - if (childNode.isExpanded()) { - updateRowKeys(childNode); - } - } - } - } -} \ No newline at end of file + public static final String DEFAULT_TYPE = "default"; + + private String type; + + private Object data; + + private List children; + + public DefaultTreeNode() { + this(null); + } + + /** + * @param data + */ + public DefaultTreeNode(Object data) { + this.type = DEFAULT_TYPE; + this.children = new LazyTreeNodeChildren(this); + this.data = data; + } + + /** + * @param data + * @param parent + */ + public DefaultTreeNode(Object data, TreeNode parent) { + this.type = DEFAULT_TYPE; + this.data = data; + this.children = new LazyTreeNodeChildren(this); + + if (parent != null) { + parent.getChildren().add(this); + } + } + + /** + * @param type + * @param data + * @param parent + */ + public DefaultTreeNode(String type, Object data, TreeNode parent) { + this.type = type; + this.data = data; + this.children = new LazyTreeNodeChildren(this); + if (parent != null) { + parent.getChildren().add(this); + } + } + + /** + * @see org.primefaces.model.TreeNode#getType() + */ + @Override + public String getType() { + return type; + } + + /** + * @param type + */ + public void setType(String type) { + this.type = type; + } + + /** + * @see org.primefaces.model.TreeNode#getData() + */ + @Override + public Object getData() { + return data; + } + + /** + * @param data + */ + public void setData(Object data) { + this.data = data; + } + + /** + * @see org.primefaces.model.TreeNode#getChildren() + */ + @Override + public List getChildren() { + return children; + } + + /** + * @param children + */ + public void setChildren(List children) { + this.children = children; + } + + /** + * @see org.primefaces.model.TreeNode#getChildCount() + */ + @Override + public int getChildCount() { + return children.size(); + } + + /** + * @see org.primefaces.model.TreeNode#isLeaf() + */ + @Override + public boolean isLeaf() { + return CollectionUtils.isEmpty(children); + } + + /** + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + return new HashCodeBuilder().append(data).toHashCode(); + } + + /** + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else if (obj == null) { + return false; + } + + if (!(obj instanceof DefaultTreeNode)) { + return false; + } + + DefaultTreeNode other = (DefaultTreeNode) obj; + + return ObjectUtils.equals(data, other.data); + } + + /** + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + if (data != null) { + return data.toString(); + } else { + return super.toString(); + } + } + + static class LazyTreeNodeChildren extends ArrayList { + + private static final long serialVersionUID = 1L; + + private TreeNode parent; + + /** + * @param parent + */ + public LazyTreeNodeChildren(TreeNode parent) { + this.parent = parent; + } + + /** + * @param node + */ + private void eraseParent(TreeNode node) { + TreeNode parentNode = node.getParent(); + + if (parentNode != null) { + parentNode.getChildren().remove(node); + node.setParent(null); + } + } + + /** + * @see java.util.ArrayList#add(java.lang.Object) + */ + @Override + public boolean add(TreeNode node) { + if (node == null) { + throw new NullArgumentException("node"); + } + + eraseParent(node); + boolean result = super.add(node); + node.setParent(parent); + updateRowKeys(parent); + return result; + } + + /** + * @see java.util.ArrayList#add(int, java.lang.Object) + */ + @Override + public void add(int index, TreeNode node) { + if (node == null) { + throw new NullArgumentException("node"); + } + + if ((index < 0) || (index > size())) { + throw new IndexOutOfBoundsException(); + } + + eraseParent(node); + super.add(index, node); + node.setParent(parent); + updateRowKeys(parent); + } + + /** + * @see java.util.ArrayList#addAll(java.util.Collection) + */ + @Override + public boolean addAll(Collection collection) { + Iterator elements = (new ArrayList(collection)) + .iterator(); + + boolean changed = false; + while (elements.hasNext()) { + TreeNode node = elements.next(); + + eraseParent(node); + super.add(node); + node.setParent(parent); + changed = true; + } + + if (changed) { + updateRowKeys(parent); + } + + return (changed); + } + + /** + * @see java.util.ArrayList#addAll(int, java.util.Collection) + */ + @Override + public boolean addAll(int index, + Collection collection) { + Iterator elements = (new ArrayList(collection)) + .iterator(); + boolean changed = false; + while (elements.hasNext()) { + TreeNode node = elements.next(); + if (node == null) { + throw new NullPointerException(); + } else { + eraseParent(node); + super.add(index++, node); + node.setParent(parent); + changed = true; + } + } + + if (changed) { + updateRowKeys(parent); + } + + return (changed); + } + + /** + * @see java.util.ArrayList#set(int, java.lang.Object) + */ + @Override + public TreeNode set(int index, TreeNode node) { + if (node == null) { + throw new NullArgumentException("node"); + } + + if ((index < 0) || (index >= size())) { + throw new IndexOutOfBoundsException(); + } + + eraseParent(node); + TreeNode previous = get(index); + super.set(index, node); + previous.setParent(null); + node.setParent(parent); + updateRowKeys(parent); + + return previous; + } + + /** + * @see java.util.ArrayList#remove(int) + */ + @Override + public TreeNode remove(int index) { + TreeNode node = get(index); + node.setParent(null); + super.remove(index); + updateRowKeys(parent); + + return node; + } + + /** + * @see java.util.ArrayList#remove(java.lang.Object) + */ + @Override + public boolean remove(Object object) { + TreeNode node = (TreeNode) object; + if (node == null) { + throw new NullPointerException(); + } + + if (super.indexOf(node) != -1) { + node.setParent(null); + } + + if (super.remove(node)) { + updateRowKeys(parent); + return true; + } else { + return false; + } + } + + /** + * @param node + */ + private void updateRowKeys(TreeNode node) { + if (!node.isExpanded()) { + return; + } + + int count = node.getChildCount(); + + List children = node.getChildren(); + + for (int i = 0; i < count; i++) { + TreeNode childNode = children.get(i); + + String rowKey; + + if (node.getParent() == null) { + rowKey = String.valueOf(i); + } else { + rowKey = node.getRowKey() + "_" + i; + } + + childNode.setRowKey(rowKey); + + if (childNode.isExpanded()) { + updateRowKeys(childNode); + } + } + } + } +} diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/tree/LazyTreeNode.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/tree/LazyTreeNode.java index 9a8fd234..fb3fc304 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/tree/LazyTreeNode.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/tree/LazyTreeNode.java @@ -7,137 +7,136 @@ public abstract class LazyTreeNode extends AbstractTreeNode { - private T object; - - private NodeData data; - - private List children; - - private NodeFilter nodeFilter; - - public LazyTreeNode() { - } - - /** - * @param object - */ - public LazyTreeNode(T object) { - setObject(object); - } - - /** - * @param object - * @return - */ - protected abstract NodeData createData(T object); - - public T getObject() { - return object; - } - - /** - * @param object - */ - public void setObject(T object) { - this.object = object; - - if (object == null) { - this.data = null; - } else { - this.data = createData(object); - } - } - - /** - * @see org.primefaces.model.TreeNode#getData() - */ - @Override - public NodeData getData() { - return data; - } - - /** - * @return the nodeFilter - */ - public NodeFilter getNodeFilter() { - return nodeFilter; - } - - /** - * @param nodeFilter - * the nodeFilter to set - */ - public void setNodeFilter(NodeFilter nodeFilter) { - this.nodeFilter = nodeFilter; - } - - /** - * @see org.primefaces.model.TreeNode#getChildCount() - */ - @Override - public int getChildCount() { - return getChildren().size(); - } - - /** - * @see org.primefaces.model.TreeNode#getChildren() - */ - @Override - public List getChildren() { - synchronized (this) { - if (!isLoaded()) { - this.children = createChildren(); - } - } - - return children; - } - - public void refresh() { - this.children = null; - } - - protected boolean isLoaded() { - return children != null; - } - - public void clearSelection() { - setSelected(false); - - if (children != null) { - for (TreeNode child : children) { - if (child instanceof LazyTreeNode) { - ((LazyTreeNode) child).clearSelection(); - } - } - } - } - - /** - * @param element - * @param child - * @return - */ - protected boolean configureChildNode(C element, - LazyTreeNode child) { - child.setParent(this); - - if (nodeFilter != null) { - if (nodeFilter.isVisible(element)) { - child.setNodeFilter(nodeFilter); - child.setExpanded(nodeFilter.isExpanded(element)); - child.setSelectable(nodeFilter.isSelectable(element)); - child.setSelected(nodeFilter.isSelected(element)); - - NodeData nodeData = child.getData(); - nodeData.setSelected(nodeFilter.isActive(element)); - } else { - return false; - } - } - - return true; - } - - protected abstract List createChildren(); + private T object; + + private NodeData data; + + private List children; + + private NodeFilter nodeFilter; + + public LazyTreeNode() { + } + + /** + * @param object + */ + public LazyTreeNode(T object) { + setObject(object); + } + + /** + * @param object + * @return + */ + protected abstract NodeData createData(T object); + + public T getObject() { + return object; + } + + /** + * @param object + */ + public void setObject(T object) { + this.object = object; + + if (object == null) { + this.data = null; + } else { + this.data = createData(object); + } + } + + /** + * @see org.primefaces.model.TreeNode#getData() + */ + @Override + public NodeData getData() { + return data; + } + + /** + * @return the nodeFilter + */ + public NodeFilter getNodeFilter() { + return nodeFilter; + } + + /** + * @param nodeFilter the nodeFilter to set + */ + public void setNodeFilter(NodeFilter nodeFilter) { + this.nodeFilter = nodeFilter; + } + + /** + * @see org.primefaces.model.TreeNode#getChildCount() + */ + @Override + public int getChildCount() { + return getChildren().size(); + } + + /** + * @see org.primefaces.model.TreeNode#getChildren() + */ + @Override + public List getChildren() { + synchronized (this) { + if (!isLoaded()) { + this.children = createChildren(); + } + } + + return children; + } + + public void refresh() { + this.children = null; + } + + protected boolean isLoaded() { + return children != null; + } + + public void clearSelection() { + setSelected(false); + + if (children != null) { + for (TreeNode child : children) { + if (child instanceof LazyTreeNode) { + ((LazyTreeNode) child).clearSelection(); + } + } + } + } + + /** + * @param element + * @param child + * @return + */ + protected boolean configureChildNode(C element, + LazyTreeNode child) { + child.setParent(this); + + if (nodeFilter != null) { + if (nodeFilter.isVisible(element)) { + child.setNodeFilter(nodeFilter); + child.setExpanded(nodeFilter.isExpanded(element)); + child.setSelectable(nodeFilter.isSelectable(element)); + child.setSelected(nodeFilter.isSelected(element)); + + NodeData nodeData = child.getData(); + nodeData.setSelected(nodeFilter.isActive(element)); + } else { + return false; + } + } + + return true; + } + + protected abstract List createChildren(); } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/tree/NodeCollector.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/tree/NodeCollector.java index bc42a2bc..19b8fced 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/tree/NodeCollector.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/tree/NodeCollector.java @@ -4,7 +4,7 @@ public interface NodeCollector { - boolean collectNode(TreeNode node); + boolean collectNode(TreeNode node); - boolean searchNode(TreeNode node); + boolean searchNode(TreeNode node); } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/tree/NodeData.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/tree/NodeData.java index 5327dd5d..d8f7087c 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/tree/NodeData.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/tree/NodeData.java @@ -4,68 +4,65 @@ public class NodeData implements Serializable { - private static final long serialVersionUID = 1504395803569600514L; + private static final long serialVersionUID = 1504395803569600514L; - private String id; + private String id; - private String name; + private String name; - private boolean selected; + private boolean selected; - public NodeData() { - } + public NodeData() { + } - /** - * @param id - * @param name - */ - public NodeData(String id, String name) { - this.id = id; - this.name = name; - } + /** + * @param id + * @param name + */ + public NodeData(String id, String name) { + this.id = id; + this.name = name; + } - /** - * @return the id - */ - public String getId() { - return id; - } + /** + * @return the id + */ + public String getId() { + return id; + } - /** - * @param id - * the id to set - */ - public void setId(String id) { - this.id = id; - } + /** + * @param id the id to set + */ + public void setId(String id) { + this.id = id; + } - /** - * @return the name - */ - public String getName() { - return name; - } + /** + * @return the name + */ + public String getName() { + return name; + } - /** - * @param name - * the name to set - */ - public void setName(String name) { - this.name = name; - } + /** + * @param name the name to set + */ + public void setName(String name) { + this.name = name; + } - /** - * @return the selected - */ - public boolean isSelected() { - return selected; - } + /** + * @return the selected + */ + public boolean isSelected() { + return selected; + } - /** - * @param selected - * the selected to set - */ - public void setSelected(boolean selected) { - this.selected = selected; - } + /** + * @param selected the selected to set + */ + public void setSelected(boolean selected) { + this.selected = selected; + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/tree/NodeFilter.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/tree/NodeFilter.java index 5f08d9e5..cb457071 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/tree/NodeFilter.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/tree/NodeFilter.java @@ -4,33 +4,33 @@ public interface NodeFilter { - /** - * @param element - * @return - */ - boolean isSelected(T element); + /** + * @param element + * @return + */ + boolean isSelected(T element); - /** - * @param element - * @return - */ - boolean isSelectable(T element); + /** + * @param element + * @return + */ + boolean isSelectable(T element); - /** - * @param element - * @return - */ - boolean isVisible(T element); + /** + * @param element + * @return + */ + boolean isVisible(T element); - /** - * @param element - * @return - */ - boolean isExpanded(T element); + /** + * @param element + * @return + */ + boolean isExpanded(T element); - /** - * @param element - * @return - */ - boolean isActive(T element); + /** + * @param element + * @return + */ + boolean isActive(T element); } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/tree/Tree.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/tree/Tree.java index 019eca53..ba6e78c2 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/tree/Tree.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/component/tree/Tree.java @@ -6,22 +6,23 @@ /** * Temporary workaround for #144. - * + * * See the related issue report here. */ public class Tree extends org.primefaces.component.tree.Tree { - /** - * @see org.primefaces.component.api.UITree#populateRowKeys(org.primefaces.model.TreeNode, - * java.util.List) - */ - @Override - public void populateRowKeys(TreeNode node, List keys) { - // Overriden to skip recursive row key population, which not only causes - // the issue described in #144, but also defeats purpose of lazy loading - // the children. - // - // super.populateRowKeys(node, keys); - } + /** + * @see + * org.primefaces.component.api.UITree#populateRowKeys(org.primefaces.model.TreeNode, + * java.util.List) + */ + @Override + public void populateRowKeys(TreeNode node, List keys) { + // Overriden to skip recursive row key population, which not only causes + // the issue described in #144, but also defeats purpose of lazy loading + // the children. + // + // super.populateRowKeys(node, keys); + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/config/Settings.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/config/Settings.java index 250bdfd6..48be8199 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/config/Settings.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/config/Settings.java @@ -4,6 +4,7 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.io.Serializable; import java.io.StringReader; import java.net.URL; import java.net.URLConnection; @@ -37,322 +38,345 @@ @ManagedBean(name = "settings", eager = true) @ApplicationScoped -public class Settings { +public class Settings implements Serializable { - public static final String CONFIG_FILE = "pivot4j.config"; + public static final String CONFIG_FILE = "pivot4j.config"; - public static final String APPLICATION_HOME = "pivot4j.home"; + public static final String APPLICATION_HOME = "pivot4j.home"; + + public static final String DEFAULT_EXTENSION = "pivot4j"; - private Logger logger = LoggerFactory.getLogger(getClass()); + private Logger logger = LoggerFactory.getLogger(getClass()); - private File applicationHome; + private File applicationHome; - private HierarchicalConfiguration configuration; + private transient HierarchicalConfiguration configuration; - private String theme; + private String theme; - private String editorTheme; + private String editorTheme; - private String resourcePrefix; + private String resourcePrefix; - private String viewParameterName; + private String viewParameterName; - private String fileParameterName; + private String fileParameterName; - private String pathParameterName; + private String pathParameterName; - private String localeAttributeName; + private String localeAttributeName; - private String extension; + private String extension; - private SortedMap availableThemes; + private String credor; - @PostConstruct - protected void initialize() { - if (logger.isInfoEnabled()) { - logger.info("Reading configuration parameters."); - } + private String aplicationHomePerClient; - FacesContext context = FacesContext.getCurrentInstance(); - ExternalContext externalContext = context.getExternalContext(); + private SortedMap availableThemes; - ProjectStage stage = context.getApplication().getProjectStage(); + @PostConstruct + protected void initialize() { + if (logger.isInfoEnabled()) { + logger.info("Reading configuration parameters."); + } - String path = StringUtils.trimToNull(externalContext - .getInitParameter(APPLICATION_HOME)); - if (path == null) { - if (logger.isInfoEnabled()) { - logger.info("Parameter 'applicationHome' is not set. Using the default path."); - } + FacesContext context = FacesContext.getCurrentInstance(); + ExternalContext externalContext = context.getExternalContext(); - path = System.getProperty("user.home") + File.separator - + ".pivot4j"; - } else if (path.endsWith(File.separator)) { - path = path.substring(0, path.length() - File.separator.length()); - } + ProjectStage stage = context.getApplication().getProjectStage(); - if (logger.isInfoEnabled()) { - logger.info("Using application home : {}", path); - } + String path = StringUtils.trimToNull(externalContext + .getInitParameter(APPLICATION_HOME)); + if (path == null) { + if (logger.isInfoEnabled()) { + logger.info("Parameter 'applicationHome' is not set. Using the default path."); + } - this.applicationHome = new File(path); + path = System.getProperty("user.home") + File.separator + + ".pivot4j"; + } else if (path.endsWith(File.separator)) { + path = path.substring(0, path.length() - File.separator.length()); + } - if (!applicationHome.exists()) { - applicationHome.mkdirs(); - } + if (logger.isInfoEnabled()) { + logger.info("Using application home : {}", path); + } - InputStream in = null; + this.applicationHome = new File(path); - try { - String configPath = StringUtils.trimToNull(externalContext - .getInitParameter(CONFIG_FILE)); - if (configPath == null || stage == ProjectStage.UnitTest) { - configPath = path + File.separator + "pivot4j-config.xml"; + if (!applicationHome.exists()) { + applicationHome.mkdirs(); + } - File configFile = new File(configPath); + InputStream in = null; - if (!configFile.exists() || stage == ProjectStage.UnitTest) { - String defaultConfig = "/WEB-INF/pivot4j-config.xml"; + try { + String configPath = StringUtils.trimToNull(externalContext + .getInitParameter(CONFIG_FILE)); + if (configPath == null || stage == ProjectStage.UnitTest) { + configPath = path + File.separator + "pivot4j-config.xml"; - if (logger.isInfoEnabled()) { - logger.info("Config file does not exist. Using default : " - + defaultConfig); - } + File configFile = new File(configPath); - ServletContext servletContext = (ServletContext) externalContext - .getContext(); + if (!configFile.exists() || stage == ProjectStage.UnitTest) { + String defaultConfig = "/WEB-INF/pivot4j-config.xml"; - String location = servletContext.getRealPath(defaultConfig); + if (logger.isInfoEnabled()) { + logger.info("Config file does not exist. Using default : " + + defaultConfig); + } - if (location != null) { - configFile = new File(location); - } - } + ServletContext servletContext = (ServletContext) externalContext + .getContext(); - if (!configFile.exists()) { - String msg = "Unable to read the default config : " - + configFile; - throw new FacesException(msg); - } + String location = servletContext.getRealPath(defaultConfig); - in = new FileInputStream(configFile); - } else { - URL url; + if (location != null) { + configFile = new File(location); + } + } - if (configPath.startsWith("classpath:")) { - url = new URL(null, configPath, - new ClasspathStreamHandler()); - } else { - url = new URL(configPath); - } - - in = url.openStream(); - - if (in == null) { - String msg = "Unable to read config from URL : " + url; - throw new FacesException(msg); - } - } - - this.configuration = readConfiguration(context, in); - } catch (IOException e) { - String msg = "Failed to read application config : " + e; - throw new FacesException(msg, e); - } catch (ConfigurationException e) { - String msg = "Invalid application config : " + e; - throw new FacesException(msg, e); - } finally { - IOUtils.closeQuietly(in); - } - - if (logger.isInfoEnabled()) { - logger.info("Pivot4J Analytics has been initialized successfully."); - } - - configuration.addConfigurationListener(new ConfigurationListener() { - - @Override - public void configurationChanged(ConfigurationEvent event) { - onConfigurationChanged(event); - } - }); - } - - /** - * @param context - * @param in - * @return - * @throws ConfigurationException - * @throws IOException - */ - protected HierarchicalConfiguration readConfiguration(FacesContext context, - InputStream in) throws ConfigurationException, IOException { - ExpressionEvaluatorFactory factory = new FreeMarkerExpressionEvaluatorFactory(); - ExpressionEvaluator evaluator = factory.createEvaluator(); - - String source = IOUtils.toString(in); - source = (String) evaluator.evaluate(source, createELContext(context)); - - XMLConfiguration config = new XMLConfiguration(); - config.load(new StringReader(source)); - - return config; - } - - /** - * @param context - * @return - */ - protected ExpressionContext createELContext(FacesContext context) { - ExpressionContext elContext = new ExpressionContext(); - - elContext.put("FS", File.separator); - - elContext.put("userHome", System.getProperty("user.dir")); - elContext.put("appHome", applicationHome.getPath()); - - ServletContext servletContext = (ServletContext) context - .getExternalContext().getContext(); - String webRoot = servletContext.getRealPath("/WEB-INF"); - - if (webRoot != null) { - elContext.put("webRoot", webRoot); - } - - return elContext; - } - - /** - * @param event - */ - protected void onConfigurationChanged(ConfigurationEvent event) { - this.editorTheme = null; - - this.resourcePrefix = null; - this.viewParameterName = null; - this.localeAttributeName = null; - } - - /** - * @return the applicationHome - */ - public File getApplicationHome() { - return applicationHome; - } - - /** - * @return the configuration - */ - public HierarchicalConfiguration getConfiguration() { - return configuration; - } - - public String getTheme() { - if (theme == null) { - this.theme = configuration.getString( - "appearances.ui-theme.default", "redmond").trim(); - } - - return theme; - } - - public String getEditorTheme() { - if (editorTheme == null) { - this.editorTheme = StringUtils.trimToNull(configuration - .getString("appearances.editor-theme")); - } - - return editorTheme; - } - - /** - * @return the availableThemes - */ - public SortedMap getAvailableThemes() { - synchronized (this) { - if (availableThemes == null) { - this.availableThemes = new TreeMap(); - - List configurations = configuration - .configurationsAt("appearances.ui-theme.available-themes.theme"); - for (HierarchicalConfiguration config : configurations) { - String name = config.getString("[@name]"); - availableThemes.put(StringUtils.capitalize(name), name); - } - } - } - - return availableThemes; - } - - public String getExtension() { - if (extension == null) { - this.extension = configuration - .getString("repository.extension", "").trim(); - } - - return extension; - } - - public String getResourcePrefix() { - if (resourcePrefix == null) { - this.resourcePrefix = StringUtils.trimToEmpty(configuration - .getString("web.resource-prefix")); - } - - return resourcePrefix; - } - - public String getViewParameterName() { - if (viewParameterName == null) { - this.viewParameterName = configuration.getString( - "web.view-parameter", "viewId").trim(); - } - - return viewParameterName; - } - - public String getFileParameterName() { - if (fileParameterName == null) { - this.fileParameterName = configuration.getString( - "web.file-parameter", "fileId").trim(); - } - - return fileParameterName; - } - - public String getPathParameterName() { - if (pathParameterName == null) { - this.pathParameterName = configuration.getString( - "web.path-parameter", "path").trim(); - } - - return pathParameterName; - } - - public String getLocaleAttributeName() { - if (localeAttributeName == null) { - this.localeAttributeName = configuration.getString( - "web.locale-attribute", "locale").trim(); - } - - return localeAttributeName; - } - - static class ClasspathStreamHandler extends URLStreamHandler { - - /** - * @see java.net.URLStreamHandler#openConnection(java.net.URL) - */ - @Override - protected URLConnection openConnection(URL u) throws IOException { - URL resourceUrl = getClass().getClassLoader().getResource( - u.getPath()); - if (resourceUrl == null) { - return null; - } - - return resourceUrl.openConnection(); - } - } + if (!configFile.exists()) { + String msg = "Unable to read the default config : " + + configFile; + throw new FacesException(msg); + } + + in = new FileInputStream(configFile); + } else { + URL url; + + if (configPath.startsWith("classpath:")) { + url = new URL(null, configPath, + new ClasspathStreamHandler()); + } else { + url = new URL(configPath); + } + + in = url.openStream(); + + if (in == null) { + String msg = "Unable to read config from URL : " + url; + throw new FacesException(msg); + } + } + + this.configuration = readConfiguration(context, in); + } catch (IOException e) { + String msg = "Failed to read application config : " + e; + throw new FacesException(msg, e); + } catch (ConfigurationException e) { + String msg = "Invalid application config : " + e; + throw new FacesException(msg, e); + } finally { + IOUtils.closeQuietly(in); + } + + if (logger.isInfoEnabled()) { + logger.info("Pivot4J Analytics has been initialized successfully."); + } + + configuration.addConfigurationListener(new ConfigurationListener() { + + @Override + public void configurationChanged(ConfigurationEvent event) { + onConfigurationChanged(event); + } + }); + } + + /** + * @param context + * @param in + * @return + * @throws ConfigurationException + * @throws IOException + */ + protected HierarchicalConfiguration readConfiguration(FacesContext context, + InputStream in) throws ConfigurationException, IOException { + ExpressionEvaluatorFactory factory = new FreeMarkerExpressionEvaluatorFactory(); + ExpressionEvaluator evaluator = factory.createEvaluator(); + + String source = IOUtils.toString(in); + source = (String) evaluator.evaluate(source, createELContext(context)); + + XMLConfiguration config = new XMLConfiguration(); + config.load(new StringReader(source)); + + return config; + } + + /** + * @param context + * @return + */ + protected ExpressionContext createELContext(FacesContext context) { + ExpressionContext elContext = new ExpressionContext(); + + elContext.put("FS", File.separator); + + elContext.put("userHome", System.getProperty("user.dir")); + elContext.put("appHome", applicationHome.getPath()); + + ServletContext servletContext = (ServletContext) context + .getExternalContext().getContext(); + String webRoot = servletContext.getRealPath("/WEB-INF"); + + if (webRoot != null) { + elContext.put("webRoot", webRoot); + } + + return elContext; + } + + /** + * @param event + */ + protected void onConfigurationChanged(ConfigurationEvent event) { + this.editorTheme = null; + + this.resourcePrefix = null; + this.viewParameterName = null; + this.localeAttributeName = null; + } + + /** + * @return the applicationHome + */ + public File getApplicationHome() { + return applicationHome; + } + + /** + * @return the configuration + */ + public HierarchicalConfiguration getConfiguration() { + return configuration; + } + + public String getAplicationHomePerClient() { + if (aplicationHomePerClient == null) { + this.aplicationHomePerClient = configuration.getString( + "repository.aplicationHomePerClient", "general").trim(); + } + return aplicationHomePerClient; + } + + public String getCredor() { + if (credor == null) { + this.credor = configuration.getString( + "web.credor-parameter", "credor").trim(); + } + + return credor; + } + + public String getTheme() { + if (theme == null) { + this.theme = configuration.getString( + "appearances.ui-theme.default", "redmond").trim(); + } + + return theme; + } + + public String getEditorTheme() { + if (editorTheme == null) { + this.editorTheme = StringUtils.trimToNull(configuration + .getString("appearances.editor-theme")); + } + + return editorTheme; + } + + /** + * @return the availableThemes + */ + public SortedMap getAvailableThemes() { + synchronized (this) { + if (availableThemes == null) { + this.availableThemes = new TreeMap(); + + List configurations = configuration + .configurationsAt("appearances.ui-theme.available-themes.theme"); + for (HierarchicalConfiguration config : configurations) { + String name = config.getString("[@name]"); + availableThemes.put(StringUtils.capitalize(name), name); + } + } + } + + return availableThemes; + } + + public String getExtension() { + if (extension == null) { + this.extension = configuration + .getString("repository.extension", DEFAULT_EXTENSION).trim(); + } + + return extension; + } + + public String getResourcePrefix() { + if (resourcePrefix == null) { + this.resourcePrefix = StringUtils.trimToEmpty(configuration + .getString("web.resource-prefix")); + } + + return resourcePrefix; + } + + public String getViewParameterName() { + if (viewParameterName == null) { + this.viewParameterName = configuration.getString( + "web.view-parameter", "viewId").trim(); + } + + return viewParameterName; + } + + public String getFileParameterName() { + if (fileParameterName == null) { + this.fileParameterName = configuration.getString( + "web.file-parameter", "fileId").trim(); + } + + return fileParameterName; + } + + public String getPathParameterName() { + if (pathParameterName == null) { + this.pathParameterName = configuration.getString( + "web.path-parameter", "path").trim(); + } + + return pathParameterName; + } + + public String getLocaleAttributeName() { + if (localeAttributeName == null) { + this.localeAttributeName = configuration.getString( + "web.locale-attribute", "locale").trim(); + } + + return localeAttributeName; + } + + static class ClasspathStreamHandler extends URLStreamHandler { + + /** + * @see java.net.URLStreamHandler#openConnection(java.net.URL) + */ + @Override + protected URLConnection openConnection(URL u) throws IOException { + URL resourceUrl = getClass().getClassLoader().getResource( + u.getPath()); + if (resourceUrl == null) { + return null; + } + + return resourceUrl.openConnection(); + } + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/converter/AggregatorConverter.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/converter/AggregatorConverter.java index f9f1af6f..9ac8741f 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/converter/AggregatorConverter.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/converter/AggregatorConverter.java @@ -11,41 +11,43 @@ @FacesConverter("aggregatorConverter") public class AggregatorConverter implements Converter { - /** - * @see javax.faces.convert.Converter#getAsObject(javax.faces.context.FacesContext, - * javax.faces.component.UIComponent, java.lang.String) - */ - @Override - public Object getAsObject(FacesContext context, UIComponent component, - String value) { - if (value == null) { - return null; - } - - ResourceBundle bundle = context.getApplication().getResourceBundle( - context, "msg"); - - String key = "label.aggregation.type." + value; - - return new SelectItem(value, bundle.getString(key)); - } - - /** - * @see javax.faces.convert.Converter#getAsString(javax.faces.context.FacesContext, - * javax.faces.component.UIComponent, java.lang.Object) - */ - @Override - public String getAsString(FacesContext context, UIComponent component, - Object value) { - if (value == null) { - return null; - } - - if (value instanceof String) { - return (String) value; - } - - SelectItem item = (SelectItem) value; - return (String) item.getValue(); - } + /** + * @see + * javax.faces.convert.Converter#getAsObject(javax.faces.context.FacesContext, + * javax.faces.component.UIComponent, java.lang.String) + */ + @Override + public Object getAsObject(FacesContext context, UIComponent component, + String value) { + if (value == null) { + return null; + } + + ResourceBundle bundle = context.getApplication().getResourceBundle( + context, "msg"); + + String key = "label.aggregation.type." + value; + + return new SelectItem(value, bundle.getString(key)); + } + + /** + * @see + * javax.faces.convert.Converter#getAsString(javax.faces.context.FacesContext, + * javax.faces.component.UIComponent, java.lang.Object) + */ + @Override + public String getAsString(FacesContext context, UIComponent component, + Object value) { + if (value == null) { + return null; + } + + if (value instanceof String) { + return (String) value; + } + + SelectItem item = (SelectItem) value; + return (String) item.getValue(); + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/converter/AxisConverter.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/converter/AxisConverter.java index 16476564..31a6a8e6 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/converter/AxisConverter.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/converter/AxisConverter.java @@ -12,43 +12,45 @@ @FacesConverter("axisConverter") public class AxisConverter implements Converter { - /** - * @see javax.faces.convert.Converter#getAsObject(javax.faces.context.FacesContext, - * javax.faces.component.UIComponent, java.lang.String) - */ - @Override - public Object getAsObject(FacesContext context, UIComponent component, - String value) { - if (value == null) { - return null; - } - - if (StringUtils.isEmpty(value)) { - return null; - } - - Standard axis = Axis.Standard.valueOf(value); - - return Axis.Factory.forOrdinal(axis.axisOrdinal()); - } - - /** - * @see javax.faces.convert.Converter#getAsString(javax.faces.context.FacesContext, - * javax.faces.component.UIComponent, java.lang.Object) - */ - @Override - public String getAsString(FacesContext context, UIComponent component, - Object value) { - if (value == null) { - return null; - } - - if (value instanceof String) { - return (String) value; - } - - Axis axis = (Axis) value; - - return axis.name(); - } + /** + * @see + * javax.faces.convert.Converter#getAsObject(javax.faces.context.FacesContext, + * javax.faces.component.UIComponent, java.lang.String) + */ + @Override + public Object getAsObject(FacesContext context, UIComponent component, + String value) { + if (value == null) { + return null; + } + + if (StringUtils.isEmpty(value)) { + return null; + } + + Standard axis = Axis.Standard.valueOf(value); + + return Axis.Factory.forOrdinal(axis.axisOrdinal()); + } + + /** + * @see + * javax.faces.convert.Converter#getAsString(javax.faces.context.FacesContext, + * javax.faces.component.UIComponent, java.lang.Object) + */ + @Override + public String getAsString(FacesContext context, UIComponent component, + Object value) { + if (value == null) { + return null; + } + + if (value instanceof String) { + return (String) value; + } + + Axis axis = (Axis) value; + + return axis.name(); + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/datasource/AbstractDataSourceInfo.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/datasource/AbstractDataSourceInfo.java index e1f07732..311a9e35 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/datasource/AbstractDataSourceInfo.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/datasource/AbstractDataSourceInfo.java @@ -8,109 +8,109 @@ public abstract class AbstractDataSourceInfo implements DataSourceInfo { - private static final long serialVersionUID = -1308857219571095791L; - - private String name; - - private String description; - - /** - * @see org.pivot4j.state.Configurable#saveSettings(org.apache.commons.configuration.HierarchicalConfiguration) - */ - @Override - public void saveSettings(HierarchicalConfiguration configuration) { - if (configuration == null) { - throw new NullArgumentException("configuration"); - } - - if (name != null) { - configuration.setProperty("name", name); - } - - if (description != null) { - configuration.setProperty("description", description); - } - } - - /** - * @see org.pivot4j.state.Configurable#restoreSettings(org.apache.commons.configuration.HierarchicalConfiguration) - */ - @Override - public void restoreSettings(HierarchicalConfiguration configuration) { - if (configuration == null) { - throw new NullArgumentException("configuration"); - } - - this.name = configuration.getString("name"); - this.description = configuration.getString("description"); - } - - /** - * @return the name - */ - public String getName() { - return name; - } - - /** - * @param name - * the name to set - */ - public void setName(String name) { - this.name = name; - } - - /** - * @return the description - */ - public String getDescription() { - return description; - } - - /** - * @param description - * the description to set - */ - public void setDescription(String description) { - this.description = description; - } - - /** - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - return new HashCodeBuilder().append(name).toHashCode(); - } - - /** - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - - if (obj == null) { - return false; - } - - if (!(obj instanceof AbstractDataSourceInfo)) { - return false; - } - - AbstractDataSourceInfo other = (AbstractDataSourceInfo) obj; - - return new EqualsBuilder().append(name, other.name).isEquals(); - } - - /** - * @see java.lang.Object#toString() - */ - @Override - public String toString() { - return new ToStringBuilder(this).append(name).append(description) - .build(); - } + private static final long serialVersionUID = -1308857219571095791L; + + private String name; + + private String description; + + /** + * @see + * org.pivot4j.state.Configurable#saveSettings(org.apache.commons.configuration.HierarchicalConfiguration) + */ + @Override + public void saveSettings(HierarchicalConfiguration configuration) { + if (configuration == null) { + throw new NullArgumentException("configuration"); + } + + if (name != null) { + configuration.setProperty("name", name); + } + + if (description != null) { + configuration.setProperty("description", description); + } + } + + /** + * @see + * org.pivot4j.state.Configurable#restoreSettings(org.apache.commons.configuration.HierarchicalConfiguration) + */ + @Override + public void restoreSettings(HierarchicalConfiguration configuration) { + if (configuration == null) { + throw new NullArgumentException("configuration"); + } + + this.name = configuration.getString("name"); + this.description = configuration.getString("description"); + } + + /** + * @return the name + */ + public String getName() { + return name; + } + + /** + * @param name the name to set + */ + public void setName(String name) { + this.name = name; + } + + /** + * @return the description + */ + public String getDescription() { + return description; + } + + /** + * @param description the description to set + */ + public void setDescription(String description) { + this.description = description; + } + + /** + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + return new HashCodeBuilder().append(name).toHashCode(); + } + + /** + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null) { + return false; + } + + if (!(obj instanceof AbstractDataSourceInfo)) { + return false; + } + + AbstractDataSourceInfo other = (AbstractDataSourceInfo) obj; + + return new EqualsBuilder().append(name, other.name).isEquals(); + } + + /** + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return new ToStringBuilder(this).append(name).append(description) + .build(); + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/datasource/AbstractDataSourceManager.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/datasource/AbstractDataSourceManager.java index ec12efc5..b953aae2 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/datasource/AbstractDataSourceManager.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/datasource/AbstractDataSourceManager.java @@ -20,235 +20,235 @@ import org.slf4j.LoggerFactory; public abstract class AbstractDataSourceManager - implements DataSourceManager { - - private Logger logger = LoggerFactory.getLogger(getClass()); - - @ManagedProperty(value = "#{settings}") - private Settings settings; - - private List definitions = new LinkedList(); - - private Map dataSources = new HashMap(); - - @PostConstruct - protected void initialize() { - if (logger.isInfoEnabled()) { - logger.info("Initializing data source manager."); - } - - registerDefinitions(); - } - - @PreDestroy - protected void destroy() { - if (logger.isInfoEnabled()) { - logger.info("Destroying data source manager."); - } - - List defs = new LinkedList(this.definitions); - - for (T definition : defs) { - unregisterDefinition(definition); - } - - this.dataSources.clear(); - this.definitions.clear(); - } - - /** - * @return the logger - */ - protected Logger getLogger() { - return logger; - } - - protected void registerDefinitions() { - List configurations = settings - .getConfiguration().configurationsAt("datasources.datasource"); - - for (HierarchicalConfiguration configuration : configurations) { - registerDefinition(configuration); - } - } - - /** - * @param configuration - */ - protected void registerDefinition(HierarchicalConfiguration configuration) { - T definition = createDataSourceDefinition(configuration); - - if (definition != null) { - registerDefinition(definition); - } - } - - /** - * @param definition - */ - protected void registerDefinition(T definition) { - if (definition == null) { - throw new NullArgumentException("definition"); - } - - synchronized (this) { - if (definitions.contains(definition)) { - unregisterDefinition(definition); - } - - definitions.add(definition); - } - } - - /** - * @param definition - */ - protected void unregisterDefinition(T definition) { - if (definition == null) { - throw new NullArgumentException("definition"); - } - - synchronized (this) { - if (logger.isInfoEnabled()) { - logger.info("Disposing data source : {}", definition); - } - - OlapDataSource dataSource = dataSources.get(definition); - - if (dataSource != null) { - if (dataSource instanceof CloseableDataSource) { - CloseableDataSource closeable = (CloseableDataSource) dataSource; - - try { - closeable.close(); - } catch (SQLException e) { - if (logger.isErrorEnabled()) { - logger.error("Failed to close data source : {}", - definition, e); - } - } - } - - dataSources.remove(definition); - } - - definitions.remove(definition); - } - } - - /** - * @param configuration - * @return - */ - protected abstract T createDataSourceDefinition( - HierarchicalConfiguration configuration); - - /** - * @param definition - * @return - */ - protected abstract OlapDataSource createDataSource(T definition); - - /** - * @param definition - * @return - */ - protected OlapDataSource getDataSource(T definition) { - synchronized (this) { - if (!dataSources.containsKey(definition)) { - if (logger.isInfoEnabled()) { - logger.info("Registering data source : {}", definition); - } - - OlapDataSource dataSource = createDataSource(definition); - dataSources.put(definition, dataSource); - } - } - - return dataSources.get(definition); - } - - /** - * @param connectionInfo - * @return - */ - protected T getDefinition(ConnectionInfo connectionInfo) { - if (connectionInfo == null) { - throw new NullArgumentException("connectionInfo"); - } - - T definition = null; - - if (connectionInfo.getCatalogName() == null) { - if (!definitions.isEmpty()) { - definition = definitions.get(0); - connectionInfo.setCatalogName(definition.getName()); - } - } else { - synchronized (this) { - for (T def : definitions) { - if (connectionInfo.getCatalogName().equals(def.getName())) { - definition = def; - break; - } - } - } - } - - return definition; - } - - protected T getDefinition(String name) { - if (name == null) { - throw new NullArgumentException("name"); - } - - T definition = null; - - synchronized (this) { - for (T def : definitions) { - if (name.equals(def.getName())) { - definition = def; - break; - } - } - } - - return definition; - } - - /** - * @see org.pivot4j.analytics.datasource.DataSourceManager#getDataSource(org.pivot4j.analytics.datasource.ConnectionInfo) - */ - @Override - public OlapDataSource getDataSource(ConnectionInfo connectionInfo) { - OlapDataSource dataSource = null; - - T definition = getDefinition(connectionInfo); - - if (definition != null) { - dataSource = getDataSource(definition); - } - - return dataSource; - } - - protected List getDefinitions() { - return Collections.unmodifiableList(definitions); - } - - /** - * @return the settings - */ - public Settings getSettings() { - return settings; - } - - /** - * @param settings - * the settings to set - */ - public void setSettings(Settings settings) { - this.settings = settings; - } -} \ No newline at end of file + implements DataSourceManager { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @ManagedProperty(value = "#{settings}") + private Settings settings; + + private List definitions = new LinkedList(); + + private Map dataSources = new HashMap(); + + @PostConstruct + protected void initialize() { + if (logger.isInfoEnabled()) { + logger.info("Initializing data source manager."); + } + + registerDefinitions(); + } + + @PreDestroy + protected void destroy() { + if (logger.isInfoEnabled()) { + logger.info("Destroying data source manager."); + } + + List defs = new LinkedList(this.definitions); + + for (T definition : defs) { + unregisterDefinition(definition); + } + + this.dataSources.clear(); + this.definitions.clear(); + } + + /** + * @return the logger + */ + protected Logger getLogger() { + return logger; + } + + protected void registerDefinitions() { + List configurations = settings + .getConfiguration().configurationsAt("datasources.datasource"); + + for (HierarchicalConfiguration configuration : configurations) { + registerDefinition(configuration); + } + } + + /** + * @param configuration + */ + protected void registerDefinition(HierarchicalConfiguration configuration) { + T definition = createDataSourceDefinition(configuration); + + if (definition != null) { + registerDefinition(definition); + } + } + + /** + * @param definition + */ + protected void registerDefinition(T definition) { + if (definition == null) { + throw new NullArgumentException("definition"); + } + + synchronized (this) { + if (definitions.contains(definition)) { + unregisterDefinition(definition); + } + + definitions.add(definition); + } + } + + /** + * @param definition + */ + protected void unregisterDefinition(T definition) { + if (definition == null) { + throw new NullArgumentException("definition"); + } + + synchronized (this) { + if (logger.isInfoEnabled()) { + logger.info("Disposing data source : {}", definition); + } + + OlapDataSource dataSource = dataSources.get(definition); + + if (dataSource != null) { + if (dataSource instanceof CloseableDataSource) { + CloseableDataSource closeable = (CloseableDataSource) dataSource; + + try { + closeable.close(); + } catch (SQLException e) { + if (logger.isErrorEnabled()) { + logger.error("Failed to close data source : {}", + definition, e); + } + } + } + + dataSources.remove(definition); + } + + definitions.remove(definition); + } + } + + /** + * @param configuration + * @return + */ + protected abstract T createDataSourceDefinition( + HierarchicalConfiguration configuration); + + /** + * @param definition + * @return + */ + protected abstract OlapDataSource createDataSource(T definition); + + /** + * @param definition + * @return + */ + protected OlapDataSource getDataSource(T definition) { + synchronized (this) { + if (!dataSources.containsKey(definition)) { + if (logger.isInfoEnabled()) { + logger.info("Registering data source : {}", definition); + } + + OlapDataSource dataSource = createDataSource(definition); + dataSources.put(definition, dataSource); + } + } + + return dataSources.get(definition); + } + + /** + * @param connectionInfo + * @return + */ + protected T getDefinition(ConnectionInfo connectionInfo) { + if (connectionInfo == null) { + throw new NullArgumentException("connectionInfo"); + } + + T definition = null; + + if (connectionInfo.getCatalogName() == null) { + if (!definitions.isEmpty()) { + definition = definitions.get(0); + connectionInfo.setCatalogName(definition.getName()); + } + } else { + synchronized (this) { + for (T def : definitions) { + if (connectionInfo.getCatalogName().equals(def.getName())) { + definition = def; + break; + } + } + } + } + + return definition; + } + + protected T getDefinition(String name) { + if (name == null) { + throw new NullArgumentException("name"); + } + + T definition = null; + + synchronized (this) { + for (T def : definitions) { + if (name.equals(def.getName())) { + definition = def; + break; + } + } + } + + return definition; + } + + /** + * @see + * org.pivot4j.analytics.datasource.DataSourceManager#getDataSource(org.pivot4j.analytics.datasource.ConnectionInfo) + */ + @Override + public OlapDataSource getDataSource(ConnectionInfo connectionInfo) { + OlapDataSource dataSource = null; + + T definition = getDefinition(connectionInfo); + + if (definition != null) { + dataSource = getDataSource(definition); + } + + return dataSource; + } + + protected List getDefinitions() { + return Collections.unmodifiableList(definitions); + } + + /** + * @return the settings + */ + public Settings getSettings() { + return settings; + } + + /** + * @param settings the settings to set + */ + public void setSettings(Settings settings) { + this.settings = settings; + } +} diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/datasource/CatalogInfo.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/datasource/CatalogInfo.java index ac1b550e..77262be8 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/datasource/CatalogInfo.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/datasource/CatalogInfo.java @@ -6,61 +6,60 @@ public class CatalogInfo implements Serializable { - private static final long serialVersionUID = 4151851551276259271L; + private static final long serialVersionUID = 4151851551276259271L; - private String name; + private String name; - private String label; + private String label; - private String description; + private String description; - /** - * @param name - * @param label - * @param description - */ - public CatalogInfo(String name, String label, String description) { - if (name == null) { - throw new NullArgumentException("name"); - } + /** + * @param name + * @param label + * @param description + */ + public CatalogInfo(String name, String label, String description) { + if (name == null) { + throw new NullArgumentException("name"); + } - this.name = name; + this.name = name; - if (label == null) { - this.label = name; - } else { - this.label = label; - } + if (label == null) { + this.label = name; + } else { + this.label = label; + } - this.description = description; - } + this.description = description; + } - /** - * @return the name - */ - public String getName() { - return name; - } + /** + * @return the name + */ + public String getName() { + return name; + } - /** - * @return the label - */ - public String getLabel() { - return label; - } + /** + * @return the label + */ + public String getLabel() { + return label; + } - /** - * @return the description - */ - public String getDescription() { - return description; - } + /** + * @return the description + */ + public String getDescription() { + return description; + } - /** - * @param description - * the description to set - */ - public void setDescription(String description) { - this.description = description; - } + /** + * @param description the description to set + */ + public void setDescription(String description) { + this.description = description; + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/datasource/ConnectionInfo.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/datasource/ConnectionInfo.java index 8422f043..1acadd02 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/datasource/ConnectionInfo.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/datasource/ConnectionInfo.java @@ -8,88 +8,88 @@ public class ConnectionInfo implements Configurable, Serializable { - private static final long serialVersionUID = 1613489385973603487L; - - private String catalogName; - - private String cubeName; - - public ConnectionInfo() { - } - - /** - * @param catalogName - * @param cubeName - */ - public ConnectionInfo(String catalogName, String cubeName) { - this.catalogName = catalogName; - this.cubeName = cubeName; - } - - /** - * @return the cubeName - */ - public String getCubeName() { - return cubeName; - } - - /** - * @param cubeName - * the cubeName to set - */ - public void setCubeName(String cubeName) { - this.cubeName = cubeName; - } - - /** - * @return the catalogName - */ - public String getCatalogName() { - return catalogName; - } - - /** - * @param catalogName - * the catalogName to set - */ - public void setCatalogName(String catalogName) { - this.catalogName = catalogName; - } - - /** - * @see org.pivot4j.state.Configurable#saveSettings(org.apache.commons.configuration.HierarchicalConfiguration) - */ - @Override - public void saveSettings(HierarchicalConfiguration configuration) { - if (configuration == null) { - throw new IllegalArgumentException( - "Configuration object cannot be null."); - } - - configuration.addProperty("catalog", catalogName); - configuration.addProperty("cube", cubeName); - } - - /** - * @see org.pivot4j.state.Configurable#restoreSettings(org.apache.commons.configuration.HierarchicalConfiguration) - */ - @Override - public void restoreSettings(HierarchicalConfiguration configuration) { - if (configuration == null) { - throw new IllegalArgumentException( - "Configuration object cannot be null."); - } - - this.catalogName = configuration.getString("catalog"); - this.cubeName = configuration.getString("cube"); - } - - /** - * @see java.lang.Object#toString() - */ - @Override - public String toString() { - return new ToStringBuilder(this).append("cubeName", cubeName) - .append("catalogName", catalogName).toString(); - } + private static final long serialVersionUID = 1613489385973603487L; + + private String catalogName; + + private String cubeName; + + public ConnectionInfo() { + } + + /** + * @param catalogName + * @param cubeName + */ + public ConnectionInfo(String catalogName, String cubeName) { + this.catalogName = catalogName; + this.cubeName = cubeName; + } + + /** + * @return the cubeName + */ + public String getCubeName() { + return cubeName; + } + + /** + * @param cubeName the cubeName to set + */ + public void setCubeName(String cubeName) { + this.cubeName = cubeName; + } + + /** + * @return the catalogName + */ + public String getCatalogName() { + return catalogName; + } + + /** + * @param catalogName the catalogName to set + */ + public void setCatalogName(String catalogName) { + this.catalogName = catalogName; + } + + /** + * @see + * org.pivot4j.state.Configurable#saveSettings(org.apache.commons.configuration.HierarchicalConfiguration) + */ + @Override + public void saveSettings(HierarchicalConfiguration configuration) { + if (configuration == null) { + throw new IllegalArgumentException( + "Configuration object cannot be null."); + } + + configuration.addProperty("catalog", catalogName); + configuration.addProperty("cube", cubeName); + } + + /** + * @see + * org.pivot4j.state.Configurable#restoreSettings(org.apache.commons.configuration.HierarchicalConfiguration) + */ + @Override + public void restoreSettings(HierarchicalConfiguration configuration) { + if (configuration == null) { + throw new IllegalArgumentException( + "Configuration object cannot be null."); + } + + this.catalogName = configuration.getString("catalog"); + this.cubeName = configuration.getString("cube"); + } + + /** + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return new ToStringBuilder(this).append("cubeName", cubeName) + .append("catalogName", catalogName).toString(); + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/datasource/CubeInfo.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/datasource/CubeInfo.java index 7143183e..560f514f 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/datasource/CubeInfo.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/datasource/CubeInfo.java @@ -6,61 +6,60 @@ public class CubeInfo implements Serializable { - private static final long serialVersionUID = -2405346074869143874L; + private static final long serialVersionUID = -2405346074869143874L; - private String name; + private String name; - private String label; + private String label; - private String description; + private String description; - /** - * @param name - * @param label - * @param description - */ - public CubeInfo(String name, String label, String description) { - if (name == null) { - throw new NullArgumentException("name"); - } + /** + * @param name + * @param label + * @param description + */ + public CubeInfo(String name, String label, String description) { + if (name == null) { + throw new NullArgumentException("name"); + } - this.name = name; + this.name = name; - if (label == null) { - this.label = name; - } else { - this.label = label; - } + if (label == null) { + this.label = name; + } else { + this.label = label; + } - this.description = description; - } + this.description = description; + } - /** - * @return the name - */ - public String getName() { - return name; - } + /** + * @return the name + */ + public String getName() { + return name; + } - /** - * @return the label - */ - public String getLabel() { - return label; - } + /** + * @return the label + */ + public String getLabel() { + return label; + } - /** - * @return the description - */ - public String getDescription() { - return description; - } + /** + * @return the description + */ + public String getDescription() { + return description; + } - /** - * @param description - * the description to set - */ - public void setDescription(String description) { - this.description = description; - } + /** + * @param description the description to set + */ + public void setDescription(String description) { + this.description = description; + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/datasource/DataSourceInfo.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/datasource/DataSourceInfo.java index 27121b1d..dec748f8 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/datasource/DataSourceInfo.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/datasource/DataSourceInfo.java @@ -6,7 +6,7 @@ public interface DataSourceInfo extends Serializable, Configurable { - String getName(); + String getName(); - String getDescription(); + String getDescription(); } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/datasource/DataSourceManager.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/datasource/DataSourceManager.java index df3597ac..a853ff95 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/datasource/DataSourceManager.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/datasource/DataSourceManager.java @@ -6,22 +6,22 @@ public interface DataSourceManager { - List getCatalogs(); + List getCatalogs(); - /** - * @param catalogName - * @return - */ - List getCubes(String catalogName); + /** + * @param catalogName + * @return + */ + List getCubes(String catalogName); - /** - * Create an OLAP datasource from the specified connection information. Note - * that the returned OlapDataSource should be able to serve multiple - * connections, so returning a SingleConnectionDataSource instance would - * cause an error for certain operations. - * - * @param connectionInfo - * @return - */ - OlapDataSource getDataSource(ConnectionInfo connectionInfo); -} \ No newline at end of file + /** + * Create an OLAP datasource from the specified connection information. Note + * that the returned OlapDataSource should be able to serve multiple + * connections, so returning a SingleConnectionDataSource instance would + * cause an error for certain operations. + * + * @param connectionInfo + * @return + */ + OlapDataSource getDataSource(ConnectionInfo connectionInfo); +} diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/datasource/simple/SimpleDataSourceInfo.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/datasource/simple/SimpleDataSourceInfo.java index 326bfa3b..a48c2274 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/datasource/simple/SimpleDataSourceInfo.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/datasource/simple/SimpleDataSourceInfo.java @@ -12,190 +12,187 @@ public class SimpleDataSourceInfo extends AbstractDataSourceInfo { - private static final long serialVersionUID = -513787516897344513L; - - private String url; - - private String userName; - - private String password; - - private String driverClass; - - private Properties properties; - - /** - * @see org.pivot4j.analytics.datasource.AbstractDataSourceInfo#saveSettings(org.apache.commons.configuration.HierarchicalConfiguration) - */ - @Override - public void saveSettings(HierarchicalConfiguration configuration) { - super.saveSettings(configuration); - - if (userName != null) { - configuration.setProperty("user", userName); - } - - if (password != null) { - configuration.setProperty("password", password); - } - - if (url != null) { - configuration.setProperty("url", url); - } - - if (driverClass != null) { - configuration.setProperty("driverClass", url); - } - - if (properties != null) { - int index = 0; - - Enumeration en = properties.elements(); - while (en.hasMoreElements()) { - String prefix = String.format("properties.property(%s)", index); - - Object key = en.nextElement(); - Object value = properties.get(key); - - configuration.setProperty(prefix + "[@name]", key); - configuration.setProperty(prefix, value); - - index++; - } - } - } - - /** - * @see org.pivot4j.analytics.datasource.AbstractDataSourceInfo#restoreSettings(org.apache.commons.configuration.HierarchicalConfiguration) - */ - @Override - public void restoreSettings(HierarchicalConfiguration configuration) { - super.restoreSettings(configuration); - - SubnodeConfiguration connectionConfig = configuration - .configurationAt("connection-info"); - - this.url = connectionConfig.getString("url"); - this.driverClass = connectionConfig.getString("driverClass"); - this.userName = connectionConfig.getString("user"); - this.password = connectionConfig.getString("password"); - this.properties = new Properties(); - - List propertiesConfig = connectionConfig - .configurationsAt("properties.property"); - for (HierarchicalConfiguration propertyConfig : propertiesConfig) { - String key = propertyConfig.getString("[@name]"); - String value = propertyConfig.getString(""); - - properties.put(key, value); - } - } - - /** - * @return the url - */ - public String getUrl() { - return url; - } - - /** - * @param url - * the url to set - */ - public void setUrl(String url) { - this.url = url; - } - - /** - * @return the userName - */ - public String getUserName() { - return userName; - } - - /** - * @param userName - * the userName to set - */ - public void setUserName(String userName) { - this.userName = userName; - } - - /** - * @return the password - */ - public String getPassword() { - return password; - } - - /** - * @param password - * the password to set - */ - public void setPassword(String password) { - this.password = password; - } - - /** - * @return the driverClass - */ - public String getDriverClass() { - return driverClass; - } - - /** - * @param driverClass - * the driverClass to set - */ - public void setDriverClass(String driverClass) { - this.driverClass = driverClass; - } - - /** - * @return the properties - */ - public Properties getProperties() { - return properties; - } - - /** - * @param properties - * the properties to set - */ - public void setProperties(Properties properties) { - this.properties = properties; - } - - /** - * @see org.pivot4j.analytics.datasource.AbstractDataSourceInfo#hashCode() - */ - @Override - public int hashCode() { - return new HashCodeBuilder().append(getName()).append(driverClass) - .append(url).toHashCode(); - } - - /** - * @see org.pivot4j.analytics.datasource.AbstractDataSourceInfo#equals(java.lang.Object) - */ - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - - if (obj == null) { - return false; - } - - if (!(obj instanceof SimpleDataSourceInfo)) { - return false; - } - - SimpleDataSourceInfo other = (SimpleDataSourceInfo) obj; - - return new EqualsBuilder().append(getName(), other.getName()) - .append(driverClass, other.driverClass).append(url, other.url) - .isEquals(); - } + private static final long serialVersionUID = -513787516897344513L; + + private String url; + + private String userName; + + private String password; + + private String driverClass; + + private Properties properties; + + /** + * @see + * org.pivot4j.analytics.datasource.AbstractDataSourceInfo#saveSettings(org.apache.commons.configuration.HierarchicalConfiguration) + */ + @Override + public void saveSettings(HierarchicalConfiguration configuration) { + super.saveSettings(configuration); + + if (userName != null) { + configuration.setProperty("user", userName); + } + + if (password != null) { + configuration.setProperty("password", password); + } + + if (url != null) { + configuration.setProperty("url", url); + } + + if (driverClass != null) { + configuration.setProperty("driverClass", url); + } + + if (properties != null) { + int index = 0; + + Enumeration en = properties.elements(); + while (en.hasMoreElements()) { + String prefix = String.format("properties.property(%s)", index); + + Object key = en.nextElement(); + Object value = properties.get(key); + + configuration.setProperty(prefix + "[@name]", key); + configuration.setProperty(prefix, value); + index++; + } + } + } + + /** + * @see + * org.pivot4j.analytics.datasource.AbstractDataSourceInfo#restoreSettings(org.apache.commons.configuration.HierarchicalConfiguration) + */ + @Override + public void restoreSettings(HierarchicalConfiguration configuration) { + super.restoreSettings(configuration); + + SubnodeConfiguration connectionConfig = configuration + .configurationAt("connection-info"); + + this.url = connectionConfig.getString("url"); + this.driverClass = connectionConfig.getString("driverClass"); + this.userName = connectionConfig.getString("user"); + this.password = connectionConfig.getString("password"); + this.properties = new Properties(); + + List propertiesConfig = connectionConfig + .configurationsAt("properties.property"); + for (HierarchicalConfiguration propertyConfig : propertiesConfig) { + String key = propertyConfig.getString("[@name]"); + String value = propertyConfig.getString(""); + + properties.put(key, value); + } + } + + /** + * @return the url + */ + public String getUrl() { + return url; + } + + /** + * @param url the url to set + */ + public void setUrl(String url) { + this.url = url; + } + + /** + * @return the userName + */ + public String getUserName() { + return userName; + } + + /** + * @param userName the userName to set + */ + public void setUserName(String userName) { + this.userName = userName; + } + + /** + * @return the password + */ + public String getPassword() { + return password; + } + + /** + * @param password the password to set + */ + public void setPassword(String password) { + this.password = password; + } + + /** + * @return the driverClass + */ + public String getDriverClass() { + return driverClass; + } + + /** + * @param driverClass the driverClass to set + */ + public void setDriverClass(String driverClass) { + this.driverClass = driverClass; + } + + /** + * @return the properties + */ + public Properties getProperties() { + return properties; + } + + /** + * @param properties the properties to set + */ + public void setProperties(Properties properties) { + this.properties = properties; + } + + /** + * @see org.pivot4j.analytics.datasource.AbstractDataSourceInfo#hashCode() + */ + @Override + public int hashCode() { + return new HashCodeBuilder().append(getName()).append(driverClass) + .append(url).toHashCode(); + } + + /** + * @see + * org.pivot4j.analytics.datasource.AbstractDataSourceInfo#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null) { + return false; + } + + if (!(obj instanceof SimpleDataSourceInfo)) { + return false; + } + + SimpleDataSourceInfo other = (SimpleDataSourceInfo) obj; + + return new EqualsBuilder().append(getName(), other.getName()) + .append(driverClass, other.driverClass).append(url, other.url) + .isEquals(); + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/datasource/simple/SimpleDataSourceManager.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/datasource/simple/SimpleDataSourceManager.java index b6462f06..3085117a 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/datasource/simple/SimpleDataSourceManager.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/datasource/simple/SimpleDataSourceManager.java @@ -1,5 +1,6 @@ package org.pivot4j.analytics.datasource.simple; +import java.io.Serializable; import java.sql.SQLException; import java.util.LinkedList; import java.util.List; @@ -24,123 +25,127 @@ @ManagedBean(name = "dataSourceManager") @ApplicationScoped public class SimpleDataSourceManager extends - AbstractDataSourceManager { - - /** - * @see org.pivot4j.analytics.datasource.AbstractDataSourceManager#initialize() - */ - @PostConstruct - protected void initialize() { - super.initialize(); - } - - /** - * @see org.pivot4j.analytics.datasource.AbstractDataSourceManager#destroy() - */ - @PreDestroy - protected void destroy() { - super.destroy(); - } - - /** - * @see org.pivot4j.analytics.datasource.AbstractDataSourceManager#createDataSourceDefinition(org.apache.commons.configuration.HierarchicalConfiguration) - */ - @Override - protected SimpleDataSourceInfo createDataSourceDefinition( - HierarchicalConfiguration configuration) { - SimpleDataSourceInfo definition = new SimpleDataSourceInfo(); - definition.restoreSettings(configuration); - - return definition; - } - - /** - * @see org.pivot4j.analytics.datasource.AbstractDataSourceManager#createDataSource(org.pivot4j.analytics.datasource.DataSourceInfo) - */ - @Override - protected OlapDataSource createDataSource(SimpleDataSourceInfo definition) { - if (definition == null) { - throw new NullArgumentException("definition"); - } - - String driverName = definition.getDriverClass(); - - try { - Class.forName(driverName); - } catch (ClassNotFoundException e) { - String msg = "Failed to load JDBC driver : " + driverName; - throw new FacesException(msg, e); - } - - SimpleOlapDataSource dataSource = new SimpleOlapDataSource(); - - dataSource.setConnectionString(definition.getUrl()); - dataSource.setUserName(definition.getUserName()); - dataSource.setPassword(definition.getPassword()); - dataSource.setConnectionProperties(definition.getProperties()); - - return dataSource; - } - - /** - * @see org.pivot4j.analytics.datasource.DataSourceManager#getCatalogs() - */ - @Override - public List getCatalogs() { - List catalogs = new LinkedList(); - - for (SimpleDataSourceInfo definition : getDefinitions()) { - catalogs.add(new CatalogInfo(definition.getName(), definition - .getName(), definition.getDescription())); - } - - return catalogs; - } - - /** - * @see org.pivot4j.analytics.datasource.DataSourceManager#getCubes(java.lang.String) - */ - @Override - public List getCubes(String catalogName) { - if (catalogName == null) { - throw new NullArgumentException("catalogName"); - } - - SimpleDataSourceInfo definition = getDefinition(catalogName); - - if (definition == null) { - throw new IllegalArgumentException( - "Data source with the given name does not exist : " - + catalogName); - } - - OlapDataSource dataSource = createDataSource(definition); - - List cubes = new LinkedList(); - - OlapConnection connection = null; - - try { - connection = dataSource.getConnection(); - - for (Cube cube : connection.getOlapSchema().getCubes()) { - if (cube.isVisible()) { - cubes.add(new CubeInfo(cube.getName(), cube.getCaption(), - cube.getDescription())); - } - } - } catch (SQLException e) { - throw new PivotException(e); - } finally { - if (connection != null) { - try { - connection.close(); - } catch (SQLException e) { - throw new PivotException(e); - } - } - } - - return cubes; - } + AbstractDataSourceManager implements Serializable { + + /** + * @see + * org.pivot4j.analytics.datasource.AbstractDataSourceManager#initialize() + */ + @PostConstruct + protected void initialize() { + super.initialize(); + } + + /** + * @see org.pivot4j.analytics.datasource.AbstractDataSourceManager#destroy() + */ + @PreDestroy + protected void destroy() { + super.destroy(); + } + + /** + * @see + * org.pivot4j.analytics.datasource.AbstractDataSourceManager#createDataSourceDefinition(org.apache.commons.configuration.HierarchicalConfiguration) + */ + @Override + protected SimpleDataSourceInfo createDataSourceDefinition( + HierarchicalConfiguration configuration) { + SimpleDataSourceInfo definition = new SimpleDataSourceInfo(); + definition.restoreSettings(configuration); + + return definition; + } + + /** + * @see + * org.pivot4j.analytics.datasource.AbstractDataSourceManager#createDataSource(org.pivot4j.analytics.datasource.DataSourceInfo) + */ + @Override + protected OlapDataSource createDataSource(SimpleDataSourceInfo definition) { + if (definition == null) { + throw new NullArgumentException("definition"); + } + + String driverName = definition.getDriverClass(); + + try { + Class.forName(driverName); + } catch (ClassNotFoundException e) { + String msg = "Failed to load JDBC driver : " + driverName; + throw new FacesException(msg, e); + } + + SimpleOlapDataSource dataSource = new SimpleOlapDataSource(); + + dataSource.setConnectionString(definition.getUrl()); + dataSource.setUserName(definition.getUserName()); + dataSource.setPassword(definition.getPassword()); + dataSource.setConnectionProperties(definition.getProperties()); + + return dataSource; + } + + /** + * @see org.pivot4j.analytics.datasource.DataSourceManager#getCatalogs() + */ + @Override + public List getCatalogs() { + List catalogs = new LinkedList(); + + for (SimpleDataSourceInfo definition : getDefinitions()) { + catalogs.add(new CatalogInfo(definition.getName(), definition + .getName(), definition.getDescription())); + } + + return catalogs; + } + + /** + * @see + * org.pivot4j.analytics.datasource.DataSourceManager#getCubes(java.lang.String) + */ + @Override + public List getCubes(String catalogName) { + if (catalogName == null) { + throw new NullArgumentException("catalogName"); + } + + SimpleDataSourceInfo definition = getDefinition(catalogName); + + if (definition == null) { + throw new IllegalArgumentException( + "Data source with the given name does not exist : " + + catalogName); + } + + OlapDataSource dataSource = createDataSource(definition); + + List cubes = new LinkedList(); + + OlapConnection connection = null; + + try { + connection = dataSource.getConnection(); + + for (Cube cube : connection.getOlapSchema().getCubes()) { + if (cube.isVisible()) { + cubes.add(new CubeInfo(cube.getName(), cube.getCaption(), + cube.getDescription())); + } + } + } catch (SQLException e) { + throw new PivotException(e); + } finally { + if (connection != null) { + try { + connection.close(); + } catch (SQLException e) { + throw new PivotException(e); + } + } + } + + return cubes; + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/exception/Pivot4JExceptionHandler.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/exception/Pivot4JExceptionHandler.java index 6dcd4a4c..be182b07 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/exception/Pivot4JExceptionHandler.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/exception/Pivot4JExceptionHandler.java @@ -17,63 +17,63 @@ public class Pivot4JExceptionHandler extends ExceptionHandlerWrapper { - private Logger logger = LoggerFactory.getLogger(getClass()); - - private ExceptionHandler handler; - - /** - * @param handler - */ - public Pivot4JExceptionHandler(ExceptionHandler handler) { - this.handler = handler; - } - - /** - * @see javax.faces.context.ExceptionHandlerWrapper#getWrapped() - */ - @Override - public ExceptionHandler getWrapped() { - return handler; - } - - /** - * @see javax.faces.context.ExceptionHandlerWrapper#handle() - */ - @Override - public void handle() throws FacesException { - Iterator it = getUnhandledExceptionQueuedEvents() - .iterator(); - while (it.hasNext()) { - ExceptionQueuedEvent event = it.next(); - ExceptionQueuedEventContext context = (ExceptionQueuedEventContext) event - .getSource(); - - FacesContext facesContext = FacesContext.getCurrentInstance(); - - ResourceBundle bundle = facesContext.getApplication() - .getResourceBundle(facesContext, "msg"); - - Throwable t = context.getException(); - Throwable cause = ExceptionUtils.getRootCause(t); - - if (cause == null) { - cause = t; - } - - String title = bundle.getString("error.unhandled.title"); - String message = bundle.getString("error.unhandled.message") - + cause; - - if (logger.isErrorEnabled()) { - logger.error(title, t); - } - - facesContext.addMessage(null, new FacesMessage( - FacesMessage.SEVERITY_ERROR, title, message)); - - it.remove(); - } - - getWrapped().handle(); - } + private Logger logger = LoggerFactory.getLogger(getClass()); + + private ExceptionHandler handler; + + /** + * @param handler + */ + public Pivot4JExceptionHandler(ExceptionHandler handler) { + this.handler = handler; + } + + /** + * @see javax.faces.context.ExceptionHandlerWrapper#getWrapped() + */ + @Override + public ExceptionHandler getWrapped() { + return handler; + } + + /** + * @see javax.faces.context.ExceptionHandlerWrapper#handle() + */ + @Override + public void handle() throws FacesException { + Iterator it = getUnhandledExceptionQueuedEvents() + .iterator(); + while (it.hasNext()) { + ExceptionQueuedEvent event = it.next(); + ExceptionQueuedEventContext context = (ExceptionQueuedEventContext) event + .getSource(); + + FacesContext facesContext = FacesContext.getCurrentInstance(); + + ResourceBundle bundle = facesContext.getApplication() + .getResourceBundle(facesContext, "msg"); + + Throwable t = context.getException(); + Throwable cause = ExceptionUtils.getRootCause(t); + + if (cause == null) { + cause = t; + } + + String title = bundle.getString("error.unhandled.title"); + String message = bundle.getString("error.unhandled.message") + + cause; + + if (logger.isErrorEnabled()) { + logger.error(title, t); + } + + facesContext.addMessage(null, new FacesMessage( + FacesMessage.SEVERITY_ERROR, title, message)); + + it.remove(); + } + + getWrapped().handle(); + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/exception/Pivot4JExceptionHandlerFactory.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/exception/Pivot4JExceptionHandlerFactory.java index 42c29e44..7b4b1ab1 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/exception/Pivot4JExceptionHandlerFactory.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/exception/Pivot4JExceptionHandlerFactory.java @@ -5,20 +5,20 @@ public class Pivot4JExceptionHandlerFactory extends ExceptionHandlerFactory { - private ExceptionHandlerFactory parent; + private ExceptionHandlerFactory parent; - /** - * @param parent - */ - public Pivot4JExceptionHandlerFactory(ExceptionHandlerFactory parent) { - this.parent = parent; - } + /** + * @param parent + */ + public Pivot4JExceptionHandlerFactory(ExceptionHandlerFactory parent) { + this.parent = parent; + } - /** - * @see javax.faces.context.ExceptionHandlerFactory#getExceptionHandler() - */ - @Override - public ExceptionHandler getExceptionHandler() { - return new Pivot4JExceptionHandler(parent.getExceptionHandler()); - } + /** + * @see javax.faces.context.ExceptionHandlerFactory#getExceptionHandler() + */ + @Override + public ExceptionHandler getExceptionHandler() { + return new Pivot4JExceptionHandler(parent.getExceptionHandler()); + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/exception/ViewExpiredExceptionHandler.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/exception/ViewExpiredExceptionHandler.java new file mode 100644 index 00000000..a24d8f98 --- /dev/null +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/exception/ViewExpiredExceptionHandler.java @@ -0,0 +1,52 @@ +/* + * ==================================================================== + * This software is subject to the terms of the Common Public License + * Agreement, available at the following URL: + * http://www.opensource.org/licenses/cpl.html . + * You must accept the terms of that agreement to use this software. + * ==================================================================== + */ +package org.pivot4j.analytics.exception; + +import java.util.Iterator; + +import javax.faces.FacesException; +import javax.faces.application.ViewExpiredException; +import javax.faces.context.ExceptionHandler; +import javax.faces.context.ExceptionHandlerWrapper; +import javax.faces.context.FacesContext; +import javax.faces.event.ExceptionQueuedEvent; + +public class ViewExpiredExceptionHandler extends ExceptionHandlerWrapper { + + private ExceptionHandler wrapped; + + public ViewExpiredExceptionHandler(ExceptionHandler wrapped) { + this.wrapped = wrapped; + } + + @Override + public void handle() throws FacesException { + FacesContext facesContext = FacesContext.getCurrentInstance(); + + for (Iterator iter = getUnhandledExceptionQueuedEvents().iterator(); iter.hasNext();) { + Throwable exception = iter.next().getContext().getException(); + + if (exception instanceof ViewExpiredException) { + facesContext.getApplication().getNavigationHandler().handleNavigation(facesContext, null, "index"); + facesContext.renderResponse(); + iter.remove(); + } else { + exception.printStackTrace(); + } + } + + getWrapped().handle(); + } + + @Override + public ExceptionHandler getWrapped() { + return wrapped; + } + +} diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/exception/ViewExpiredExceptionHandlerFactory.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/exception/ViewExpiredExceptionHandlerFactory.java new file mode 100644 index 00000000..aedfd301 --- /dev/null +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/exception/ViewExpiredExceptionHandlerFactory.java @@ -0,0 +1,29 @@ +/* + * ==================================================================== + * This software is subject to the terms of the Common Public License + * Agreement, available at the following URL: + * http://www.opensource.org/licenses/cpl.html . + * You must accept the terms of that agreement to use this software. + * ==================================================================== + */ +package org.pivot4j.analytics.exception; + + +import javax.faces.context.ExceptionHandler; +import javax.faces.context.ExceptionHandlerFactory; + +public class ViewExpiredExceptionHandlerFactory extends ExceptionHandlerFactory { + + private ExceptionHandlerFactory parent; + + public ViewExpiredExceptionHandlerFactory(ExceptionHandlerFactory parent) { + this.parent = parent; + } + + @Override + public ExceptionHandler getExceptionHandler() { + + return new ViewExpiredExceptionHandler(parent.getExceptionHandler()); + } + +} \ No newline at end of file diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/listener/LocaleInitializer.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/listener/LocaleInitializer.java index c2347f82..a245b3c9 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/listener/LocaleInitializer.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/listener/LocaleInitializer.java @@ -21,61 +21,61 @@ public class LocaleInitializer implements PhaseListener { - private static final long serialVersionUID = -2477093113131236331L; + private static final long serialVersionUID = -2477093113131236331L; - /** - * @return - */ - @Override - public PhaseId getPhaseId() { - return PhaseId.RESTORE_VIEW; - } + /** + * @return + */ + @Override + public PhaseId getPhaseId() { + return PhaseId.RESTORE_VIEW; + } - /** - * @param event - */ - @Override - public void beforePhase(PhaseEvent event) { - } + /** + * @param event + */ + @Override + public void beforePhase(PhaseEvent event) { + } - /** - * @param event - */ - @Override - public void afterPhase(PhaseEvent event) { - FacesContext context = FacesContext.getCurrentInstance(); - ExternalContext externalContext = context.getExternalContext(); + /** + * @param event + */ + @Override + public void afterPhase(PhaseEvent event) { + FacesContext context = FacesContext.getCurrentInstance(); + ExternalContext externalContext = context.getExternalContext(); - Settings settings = (Settings) externalContext.getApplicationMap().get( - "settings"); + Settings settings = (Settings) externalContext.getApplicationMap().get( + "settings"); - Locale locale = null; + Locale locale = null; - HttpSession session = (HttpSession) externalContext.getSession(false); + HttpSession session = (HttpSession) externalContext.getSession(false); - if (session != null) { - String key = settings.getLocaleAttributeName(); + if (session != null) { + String key = settings.getLocaleAttributeName(); - if (key != null) { - Object value = session.getAttribute(key); - if (value instanceof Locale) { - locale = (Locale) value; - } else if (value != null) { - String[] args = value.toString().split("_"); + if (key != null) { + Object value = session.getAttribute(key); + if (value instanceof Locale) { + locale = (Locale) value; + } else if (value != null) { + String[] args = value.toString().split("_"); - if (args.length == 1) { - locale = new Locale(args[0]); - } else if (args.length == 2) { - locale = new Locale(args[0], args[1]); - } else if (args.length == 3) { - locale = new Locale(args[0], args[1], args[2]); - } - } - } - } + if (args.length == 1) { + locale = new Locale(args[0]); + } else if (args.length == 2) { + locale = new Locale(args[0], args[1]); + } else if (args.length == 3) { + locale = new Locale(args[0], args[1], args[2]); + } + } + } + } - if (locale != null && context.getViewRoot() != null) { - context.getViewRoot().setLocale(locale); - } - } + if (locale != null && context.getViewRoot() != null) { + context.getViewRoot().setLocale(locale); + } + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/AbstractPropertyEditor.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/AbstractPropertyEditor.java index 1eff7a3a..df35bec7 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/AbstractPropertyEditor.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/AbstractPropertyEditor.java @@ -9,67 +9,69 @@ public abstract class AbstractPropertyEditor implements PropertyEditor { - /** - * @see org.pivot4j.analytics.property.PropertyEditor#getValue(org.pivot4j.analytics.property.PropertyDescriptor, - * org.pivot4j.ui.property.RenderPropertyList) - */ - @Override - public Object getValue(PropertyDescriptor descriptor, - RenderPropertyList properties) { - if (descriptor == null) { - throw new NullArgumentException("descriptor"); - } + /** + * @see + * org.pivot4j.analytics.property.PropertyEditor#getValue(org.pivot4j.analytics.property.PropertyDescriptor, + * org.pivot4j.ui.property.RenderPropertyList) + */ + @Override + public Object getValue(PropertyDescriptor descriptor, + RenderPropertyList properties) { + if (descriptor == null) { + throw new NullArgumentException("descriptor"); + } - if (properties == null) { - throw new NullArgumentException("properties"); - } + if (properties == null) { + throw new NullArgumentException("properties"); + } - RenderProperty property = properties.getRenderProperty(descriptor.getKey()); + RenderProperty property = properties.getRenderProperty(descriptor.getKey()); - if (property == null) { - return null; - } + if (property == null) { + return null; + } - Object value = null; + Object value = null; - if (property instanceof SimpleRenderProperty) { - value = getValue((SimpleRenderProperty) property); - } + if (property instanceof SimpleRenderProperty) { + value = getValue((SimpleRenderProperty) property); + } - return value; - } + return value; + } - /** - * @param property - * @return - */ - protected Object getValue(SimpleRenderProperty property) { - return property.getValue(); - } + /** + * @param property + * @return + */ + protected Object getValue(SimpleRenderProperty property) { + return property.getValue(); + } - /** - * @see org.pivot4j.analytics.property.PropertyEditor#setValue(org.pivot4j.analytics.property.PropertyDescriptor, - * org.pivot4j.ui.property.RenderPropertyList, java.lang.Object) - */ - @Override - public void setValue(PropertyDescriptor descriptor, - RenderPropertyList properties, Object value) { - if (descriptor == null) { - throw new NullArgumentException("descriptor"); - } + /** + * @see + * org.pivot4j.analytics.property.PropertyEditor#setValue(org.pivot4j.analytics.property.PropertyDescriptor, + * org.pivot4j.ui.property.RenderPropertyList, java.lang.Object) + */ + @Override + public void setValue(PropertyDescriptor descriptor, + RenderPropertyList properties, Object value) { + if (descriptor == null) { + throw new NullArgumentException("descriptor"); + } - if (properties == null) { - throw new NullArgumentException("properties"); - } + if (properties == null) { + throw new NullArgumentException("properties"); + } - String stringValue = StringUtils - .trimToNull(ObjectUtils.toString(value)); + String stringValue = StringUtils + .trimToNull(ObjectUtils.toString(value)); - if (stringValue == null) { - properties.removeRenderProperty(descriptor.getKey()); - } else { - properties.setRenderProperty(new SimpleRenderProperty(descriptor.getKey(), - stringValue)); - } - } + if (stringValue == null) { + properties.removeRenderProperty(descriptor.getKey()); + } else { + properties.setRenderProperty(new SimpleRenderProperty(descriptor.getKey(), + stringValue)); + } + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/AbstractPropertyInputEditor.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/AbstractPropertyInputEditor.java index 3740dc9b..37377873 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/AbstractPropertyInputEditor.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/AbstractPropertyInputEditor.java @@ -10,46 +10,47 @@ import org.primefaces.behavior.ajax.AjaxBehaviorListenerImpl; public abstract class AbstractPropertyInputEditor extends - AbstractPropertyEditor { - - /** - * @see org.pivot4j.analytics.property.PropertyEditor#createComponent(org.pivot4j.analytics.property.PropertyDescriptor, - * javax.faces.component.UIComponent, javax.el.ValueExpression, - * javax.el.MethodExpression, java.lang.String) - */ - @Override - public void createComponent(PropertyDescriptor descriptor, - UIComponent parent, ValueExpression expression, - MethodExpression listener, String update) { - FacesContext context = FacesContext.getCurrentInstance(); - - UIInput input = createInput(descriptor, parent, context); - - input.setValueExpression("value", expression); - - String eventName = getEventName(); - if (eventName != null) { - AjaxBehavior behavior = new AjaxBehavior(); - behavior.addAjaxBehaviorListener(new AjaxBehaviorListenerImpl( - listener, listener)); - behavior.setUpdate(update); - - input.addClientBehavior("change", behavior); - } - - parent.getChildren().add(input); - } - - protected String getEventName() { - return "change"; - } - - /** - * @param descriptor - * @param parent - * @param context - * @return - */ - protected abstract UIInput createInput(PropertyDescriptor descriptor, - UIComponent parent, FacesContext context); + AbstractPropertyEditor { + + /** + * @see + * org.pivot4j.analytics.property.PropertyEditor#createComponent(org.pivot4j.analytics.property.PropertyDescriptor, + * javax.faces.component.UIComponent, javax.el.ValueExpression, + * javax.el.MethodExpression, java.lang.String) + */ + @Override + public void createComponent(PropertyDescriptor descriptor, + UIComponent parent, ValueExpression expression, + MethodExpression listener, String update) { + FacesContext context = FacesContext.getCurrentInstance(); + + UIInput input = createInput(descriptor, parent, context); + + input.setValueExpression("value", expression); + + String eventName = getEventName(); + if (eventName != null) { + AjaxBehavior behavior = new AjaxBehavior(); + behavior.addAjaxBehaviorListener(new AjaxBehaviorListenerImpl( + listener, listener)); + behavior.setUpdate(update); + + input.addClientBehavior("change", behavior); + } + + parent.getChildren().add(input); + } + + protected String getEventName() { + return "change"; + } + + /** + * @param descriptor + * @param parent + * @param context + * @return + */ + protected abstract UIInput createInput(PropertyDescriptor descriptor, + UIComponent parent, FacesContext context); } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/ColorPropertyEditor.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/ColorPropertyEditor.java index 367222a9..58cc2f1f 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/ColorPropertyEditor.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/ColorPropertyEditor.java @@ -12,51 +12,54 @@ public class ColorPropertyEditor extends AbstractPropertyInputEditor { - /** - * @see org.pivot4j.analytics.property.AbstractPropertyInputEditor#createInput - * (org.pivot4j.analytics.property.PropertyDescriptor, - * javax.faces.component.UIComponent, javax.faces.context.FacesContext) - */ - @Override - protected UIInput createInput(PropertyDescriptor descriptor, - UIComponent parent, FacesContext context) { - Application application = FacesContext.getCurrentInstance() - .getApplication(); - - return (UIInput) application - .createComponent(AjaxColorPicker.COMPONENT_TYPE); - } - - /** - * @see org.pivot4j.analytics.property.AbstractPropertyEditor#getValue(org.pivot4j.ui.property.SimpleRenderProperty) - */ - @Override - protected Object getValue(SimpleRenderProperty property) { - String value = StringUtils - .trimToNull((String) super.getValue(property)); - - if (value != null && value.matches("#[a-fA-F0-9]+")) { - value = value.substring(1); - } else { - value = null; - } - - return value; - } - - /** - * @see org.pivot4j.analytics.property.AbstractPropertyEditor#setValue(org.pivot4j.analytics.property.PropertyDescriptor, - * org.pivot4j.ui.property.RenderPropertyList, java.lang.Object) - */ - @Override - public void setValue(PropertyDescriptor descriptor, - RenderPropertyList properties, Object value) { - String stringValue = StringUtils.trimToNull((String) value); - - if (stringValue != null && stringValue.matches("[a-fA-F0-9]+")) { - stringValue = "#" + stringValue; - } - - super.setValue(descriptor, properties, stringValue); - } + /** + * @see + * org.pivot4j.analytics.property.AbstractPropertyInputEditor#createInput + * (org.pivot4j.analytics.property.PropertyDescriptor, + * javax.faces.component.UIComponent, javax.faces.context.FacesContext) + */ + @Override + protected UIInput createInput(PropertyDescriptor descriptor, + UIComponent parent, FacesContext context) { + Application application = FacesContext.getCurrentInstance() + .getApplication(); + + return (UIInput) application + .createComponent(AjaxColorPicker.COMPONENT_TYPE); + } + + /** + * @see + * org.pivot4j.analytics.property.AbstractPropertyEditor#getValue(org.pivot4j.ui.property.SimpleRenderProperty) + */ + @Override + protected Object getValue(SimpleRenderProperty property) { + String value = StringUtils + .trimToNull((String) super.getValue(property)); + + if (value != null && value.matches("#[a-fA-F0-9]+")) { + value = value.substring(1); + } else { + value = null; + } + + return value; + } + + /** + * @see + * org.pivot4j.analytics.property.AbstractPropertyEditor#setValue(org.pivot4j.analytics.property.PropertyDescriptor, + * org.pivot4j.ui.property.RenderPropertyList, java.lang.Object) + */ + @Override + public void setValue(PropertyDescriptor descriptor, + RenderPropertyList properties, Object value) { + String stringValue = StringUtils.trimToNull((String) value); + + if (stringValue != null && stringValue.matches("[a-fA-F0-9]+")) { + stringValue = "#" + stringValue; + } + + super.setValue(descriptor, properties, stringValue); + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/FontFamilyPropertyEditor.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/FontFamilyPropertyEditor.java index 8585ef04..ca9e0d22 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/FontFamilyPropertyEditor.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/FontFamilyPropertyEditor.java @@ -12,60 +12,62 @@ public class FontFamilyPropertyEditor extends SelectStringPropertyEditor { - public FontFamilyPropertyEditor() { - super(Arrays.asList(new UISelectItem[] { createItem(""), - createItem("serif"), createItem("sans-serif"), - createItem("monospace"), createItem("cursive"), - createItem("fantasy") })); - } + public FontFamilyPropertyEditor() { + super(Arrays.asList(new UISelectItem[]{createItem(""), + createItem("serif"), createItem("sans-serif"), + createItem("monospace"), createItem("cursive"), + createItem("fantasy")})); + } - /** - * @param fontName - * @return - */ - private static UISelectItem createItem(String fontName) { - UISelectItem item = new UISelectItem(); - item.setItemLabel(fontName); - item.setItemValue(fontName); + /** + * @param fontName + * @return + */ + private static UISelectItem createItem(String fontName) { + UISelectItem item = new UISelectItem(); + item.setItemLabel(fontName); + item.setItemValue(fontName); - return item; - } + return item; + } - /** - * @see org.pivot4j.analytics.property.AbstractPropertyEditor#getValue(org.pivot4j.ui.property.SimpleRenderProperty) - */ - @Override - protected Object getValue(SimpleRenderProperty property) { - String stringValue = StringUtils.trimToNull(property.getValue()); + /** + * @see + * org.pivot4j.analytics.property.AbstractPropertyEditor#getValue(org.pivot4j.ui.property.SimpleRenderProperty) + */ + @Override + protected Object getValue(SimpleRenderProperty property) { + String stringValue = StringUtils.trimToNull(property.getValue()); - List items = getItems(); + List items = getItems(); - boolean matches = false; + boolean matches = false; - if (stringValue != null && items != null) { - for (UISelectItem item : items) { - if (stringValue.equals(item.getItemValue())) { - matches = true; - break; - } - } - } + if (stringValue != null && items != null) { + for (UISelectItem item : items) { + if (stringValue.equals(item.getItemValue())) { + matches = true; + break; + } + } + } - if (!matches) { - stringValue = null; - } + if (!matches) { + stringValue = null; + } - return stringValue; - } + return stringValue; + } - /** - * @see org.pivot4j.analytics.property.AbstractPropertyEditor#setValue(org.pivot4j.analytics.property.PropertyDescriptor, - * org.pivot4j.ui.property.RenderPropertyList, java.lang.Object) - */ - @Override - public void setValue(PropertyDescriptor descriptor, - RenderPropertyList properties, Object value) { - super.setValue(descriptor, properties, - StringUtils.trimToNull(ObjectUtils.toString(value))); - } + /** + * @see + * org.pivot4j.analytics.property.AbstractPropertyEditor#setValue(org.pivot4j.analytics.property.PropertyDescriptor, + * org.pivot4j.ui.property.RenderPropertyList, java.lang.Object) + */ + @Override + public void setValue(PropertyDescriptor descriptor, + RenderPropertyList properties, Object value) { + super.setValue(descriptor, properties, + StringUtils.trimToNull(ObjectUtils.toString(value))); + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/FontSizePropertyEditor.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/FontSizePropertyEditor.java index a1d81e39..06413886 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/FontSizePropertyEditor.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/FontSizePropertyEditor.java @@ -12,60 +12,63 @@ public class FontSizePropertyEditor extends IntegerPropertyEditor { - public FontSizePropertyEditor() { - super(1, null, 6); - } + public FontSizePropertyEditor() { + super(1, null, 6); + } - /** - * @see org.pivot4j.analytics.property.AbstractPropertyInputEditor#createComponent(org.pivot4j.analytics.property.PropertyDescriptor, - * javax.faces.component.UIComponent, javax.el.ValueExpression, - * javax.el.MethodExpression, java.lang.String) - */ - @Override - public void createComponent(PropertyDescriptor descriptor, - UIComponent parent, ValueExpression expression, - MethodExpression listener, String update) { - super.createComponent(descriptor, parent, expression, listener, update); + /** + * @see + * org.pivot4j.analytics.property.AbstractPropertyInputEditor#createComponent(org.pivot4j.analytics.property.PropertyDescriptor, + * javax.faces.component.UIComponent, javax.el.ValueExpression, + * javax.el.MethodExpression, java.lang.String) + */ + @Override + public void createComponent(PropertyDescriptor descriptor, + UIComponent parent, ValueExpression expression, + MethodExpression listener, String update) { + super.createComponent(descriptor, parent, expression, listener, update); - HtmlOutputText unitText = new HtmlOutputText(); - unitText.setStyleClass("unit-text"); - unitText.setValue("(pt)"); + HtmlOutputText unitText = new HtmlOutputText(); + unitText.setStyleClass("unit-text"); + unitText.setValue("(pt)"); - parent.getChildren().add(unitText); - } + parent.getChildren().add(unitText); + } - /** - * @see org.pivot4j.analytics.property.IntegerPropertyEditor#getValue(org.pivot4j.ui.property.SimpleRenderProperty) - */ - @Override - protected Object getValue(SimpleRenderProperty property) { - String stringValue = StringUtils.trimToNull(property.getValue()); + /** + * @see + * org.pivot4j.analytics.property.IntegerPropertyEditor#getValue(org.pivot4j.ui.property.SimpleRenderProperty) + */ + @Override + protected Object getValue(SimpleRenderProperty property) { + String stringValue = StringUtils.trimToNull(property.getValue()); - Object value = null; + Object value = null; - if (stringValue != null && stringValue.matches("[0-9]+pt")) { - value = Integer.parseInt(stringValue.substring(0, - stringValue.length() - 2)); - } else { - value = null; - } + if (stringValue != null && stringValue.matches("[0-9]+pt")) { + value = Integer.parseInt(stringValue.substring(0, + stringValue.length() - 2)); + } else { + value = null; + } - return value; - } + return value; + } - /** - * @see org.pivot4j.analytics.property.AbstractPropertyEditor#setValue(org.pivot4j.analytics.property.PropertyDescriptor, - * org.pivot4j.ui.property.RenderPropertyList, java.lang.Object) - */ - @Override - public void setValue(PropertyDescriptor descriptor, - RenderPropertyList properties, Object value) { - String fontSize = StringUtils.trimToNull(ObjectUtils.toString(value)); + /** + * @see + * org.pivot4j.analytics.property.AbstractPropertyEditor#setValue(org.pivot4j.analytics.property.PropertyDescriptor, + * org.pivot4j.ui.property.RenderPropertyList, java.lang.Object) + */ + @Override + public void setValue(PropertyDescriptor descriptor, + RenderPropertyList properties, Object value) { + String fontSize = StringUtils.trimToNull(ObjectUtils.toString(value)); - if (fontSize != null) { - fontSize += "pt"; - } + if (fontSize != null) { + fontSize += "pt"; + } - super.setValue(descriptor, properties, fontSize); - } + super.setValue(descriptor, properties, fontSize); + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/FontStylePropertyEditor.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/FontStylePropertyEditor.java index c6ea14be..d919c8c7 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/FontStylePropertyEditor.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/FontStylePropertyEditor.java @@ -18,84 +18,87 @@ public class FontStylePropertyEditor extends AbstractPropertyInputEditor { - private Collection styles = Arrays.asList("", "normal", "bold", - "italic", "bolditalic"); - - /** - * @see org.pivot4j.analytics.property.AbstractPropertyInputEditor#createInput(org.pivot4j.analytics.property.PropertyDescriptor, - * javax.faces.component.UIComponent, javax.faces.context.FacesContext) - */ - @Override - protected UIInput createInput(PropertyDescriptor descriptor, - UIComponent parent, FacesContext context) { - Application application = FacesContext.getCurrentInstance() - .getApplication(); - SelectOneMenu select = (SelectOneMenu) application - .createComponent(SelectOneMenu.COMPONENT_TYPE); - - ResourceBundle resources = application - .getResourceBundle(context, "msg"); - - for (String style : styles) { - select.getChildren().add(createItem(style, resources)); - } - - return select; - } - - /** - * @param styleName - * @param resources - * @return - */ - private UISelectItem createItem(String styleName, ResourceBundle resources) { - UISelectItem item = new UISelectItem(); - - if (StringUtils.isEmpty(styleName)) { - item.setItemLabel(""); - } else { - String key = "properties.fontStyle.option." + styleName; - item.setItemLabel(resources.getString(key)); - } - - item.setItemValue(styleName); - - return item; - } - - /** - * @see org.pivot4j.analytics.property.AbstractPropertyEditor#getValue(org.pivot4j.ui.property.SimpleRenderProperty) - */ - @Override - protected Object getValue(SimpleRenderProperty property) { - String stringValue = StringUtils.trimToNull(property.getValue()); - - boolean matches = false; - - if (stringValue != null) { - for (String style : styles) { - if (stringValue.equals(style)) { - matches = true; - break; - } - } - } - - if (!matches) { - stringValue = null; - } - - return stringValue; - } - - /** - * @see org.pivot4j.analytics.property.AbstractPropertyEditor#setValue(org.pivot4j.analytics.property.PropertyDescriptor, - * org.pivot4j.ui.property.RenderPropertyList, java.lang.Object) - */ - @Override - public void setValue(PropertyDescriptor descriptor, - RenderPropertyList properties, Object value) { - super.setValue(descriptor, properties, - StringUtils.trimToNull(ObjectUtils.toString(value))); - } + private Collection styles = Arrays.asList("", "normal", "bold", + "italic", "bolditalic"); + + /** + * @see + * org.pivot4j.analytics.property.AbstractPropertyInputEditor#createInput(org.pivot4j.analytics.property.PropertyDescriptor, + * javax.faces.component.UIComponent, javax.faces.context.FacesContext) + */ + @Override + protected UIInput createInput(PropertyDescriptor descriptor, + UIComponent parent, FacesContext context) { + Application application = FacesContext.getCurrentInstance() + .getApplication(); + SelectOneMenu select = (SelectOneMenu) application + .createComponent(SelectOneMenu.COMPONENT_TYPE); + + ResourceBundle resources = application + .getResourceBundle(context, "msg"); + + for (String style : styles) { + select.getChildren().add(createItem(style, resources)); + } + + return select; + } + + /** + * @param styleName + * @param resources + * @return + */ + private UISelectItem createItem(String styleName, ResourceBundle resources) { + UISelectItem item = new UISelectItem(); + + if (StringUtils.isEmpty(styleName)) { + item.setItemLabel(""); + } else { + String key = "properties.fontStyle.option." + styleName; + item.setItemLabel(resources.getString(key)); + } + + item.setItemValue(styleName); + + return item; + } + + /** + * @see + * org.pivot4j.analytics.property.AbstractPropertyEditor#getValue(org.pivot4j.ui.property.SimpleRenderProperty) + */ + @Override + protected Object getValue(SimpleRenderProperty property) { + String stringValue = StringUtils.trimToNull(property.getValue()); + + boolean matches = false; + + if (stringValue != null) { + for (String style : styles) { + if (stringValue.equals(style)) { + matches = true; + break; + } + } + } + + if (!matches) { + stringValue = null; + } + + return stringValue; + } + + /** + * @see + * org.pivot4j.analytics.property.AbstractPropertyEditor#setValue(org.pivot4j.analytics.property.PropertyDescriptor, + * org.pivot4j.ui.property.RenderPropertyList, java.lang.Object) + */ + @Override + public void setValue(PropertyDescriptor descriptor, + RenderPropertyList properties, Object value) { + super.setValue(descriptor, properties, + StringUtils.trimToNull(ObjectUtils.toString(value))); + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/IntegerPropertyEditor.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/IntegerPropertyEditor.java index 20a4f4be..482817f3 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/IntegerPropertyEditor.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/IntegerPropertyEditor.java @@ -12,116 +12,116 @@ public class IntegerPropertyEditor extends AbstractPropertyInputEditor { - private Integer minimumValue; - - private Integer maximumValue; - - private Integer size; - - public IntegerPropertyEditor() { - - } - - /** - * @param minimumValue - * @param maximumValue - * @param size - */ - public IntegerPropertyEditor(Integer minimumValue, Integer maximumValue, - Integer size) { - this.minimumValue = minimumValue; - this.maximumValue = maximumValue; - this.size = size; - } - - /** - * @see org.pivot4j.analytics.property.AbstractPropertyInputEditor#createInput - * (org.pivot4j.analytics.property.PropertyDescriptor, - * javax.faces.component.UIComponent, javax.faces.context.FacesContext) - */ - @Override - protected UIInput createInput(PropertyDescriptor descriptor, - UIComponent parent, FacesContext context) { - Application application = FacesContext.getCurrentInstance() - .getApplication(); - Spinner spinner = (Spinner) application - .createComponent(Spinner.COMPONENT_TYPE); - - if (minimumValue != null) { - spinner.setMin(minimumValue); - } - - if (maximumValue != null) { - spinner.setMax(maximumValue); - } - - if (size != null) { - spinner.setSize(size); - } - - return spinner; - } - - /** - * @see org.pivot4j.analytics.property.AbstractPropertyEditor#getValue(org.pivot4j.ui.property.SimpleRenderProperty) - */ - @Override - protected Object getValue(SimpleRenderProperty property) { - String stringValue = StringUtils.trimToNull((String) super - .getValue(property)); - - Object value = null; - - if (NumberUtils.isNumber(stringValue)) { - value = Integer.parseInt(stringValue); - } else { - value = null; - } - - return value; - } - - /** - * @return the minimumValue - */ - public Integer getMinimumValue() { - return minimumValue; - } - - /** - * @param minimumValue - * the minimumValue to set - */ - public void setMinimumValue(Integer minimumValue) { - this.minimumValue = minimumValue; - } - - /** - * @return the maximumValue - */ - public Integer getMaximumValue() { - return maximumValue; - } - - /** - * @param maximumValue - * the maximumValue to set - */ - public void setMaximumValue(Integer maximumValue) { - this.maximumValue = maximumValue; - } - - /** - * @return the size - */ - public Integer getSize() { - return size; - } - - /** - * @param size the size to set - */ - public void setSize(Integer size) { - this.size = size; - } + private Integer minimumValue; + + private Integer maximumValue; + + private Integer size; + + public IntegerPropertyEditor() { + + } + + /** + * @param minimumValue + * @param maximumValue + * @param size + */ + public IntegerPropertyEditor(Integer minimumValue, Integer maximumValue, + Integer size) { + this.minimumValue = minimumValue; + this.maximumValue = maximumValue; + this.size = size; + } + + /** + * @see + * org.pivot4j.analytics.property.AbstractPropertyInputEditor#createInput + * (org.pivot4j.analytics.property.PropertyDescriptor, + * javax.faces.component.UIComponent, javax.faces.context.FacesContext) + */ + @Override + protected UIInput createInput(PropertyDescriptor descriptor, + UIComponent parent, FacesContext context) { + Application application = FacesContext.getCurrentInstance() + .getApplication(); + Spinner spinner = (Spinner) application + .createComponent(Spinner.COMPONENT_TYPE); + + if (minimumValue != null) { + spinner.setMin(minimumValue); + } + + if (maximumValue != null) { + spinner.setMax(maximumValue); + } + + if (size != null) { + spinner.setSize(size); + } + + return spinner; + } + + /** + * @see + * org.pivot4j.analytics.property.AbstractPropertyEditor#getValue(org.pivot4j.ui.property.SimpleRenderProperty) + */ + @Override + protected Object getValue(SimpleRenderProperty property) { + String stringValue = StringUtils.trimToNull((String) super + .getValue(property)); + + Object value = null; + + if (NumberUtils.isNumber(stringValue)) { + value = Integer.parseInt(stringValue); + } else { + value = null; + } + + return value; + } + + /** + * @return the minimumValue + */ + public Integer getMinimumValue() { + return minimumValue; + } + + /** + * @param minimumValue the minimumValue to set + */ + public void setMinimumValue(Integer minimumValue) { + this.minimumValue = minimumValue; + } + + /** + * @return the maximumValue + */ + public Integer getMaximumValue() { + return maximumValue; + } + + /** + * @param maximumValue the maximumValue to set + */ + public void setMaximumValue(Integer maximumValue) { + this.maximumValue = maximumValue; + } + + /** + * @return the size + */ + public Integer getSize() { + return size; + } + + /** + * @param size the size to set + */ + public void setSize(Integer size) { + this.size = size; + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/PropertyCategory.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/PropertyCategory.java index 3e4606c1..f2bab6e9 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/PropertyCategory.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/PropertyCategory.java @@ -3,5 +3,5 @@ //XXX Should use RenderPropertyCategory instead. public enum PropertyCategory { - Header, Cell + Header, Cell } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/PropertyDescriptor.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/PropertyDescriptor.java index cc6c5b36..fca73e1c 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/PropertyDescriptor.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/PropertyDescriptor.java @@ -1,108 +1,108 @@ package org.pivot4j.analytics.property; +import java.io.Serializable; import java.util.ResourceBundle; import javax.faces.context.FacesContext; import org.apache.commons.lang.NullArgumentException; -public class PropertyDescriptor { - - private String key; - - private PropertyCategory category; - - private String icon; - - private PropertyEditor editor; - - /** - * @param category - * @param key - * @param icon - * @param editor - */ - public PropertyDescriptor(PropertyCategory category, String key, - String icon, PropertyEditor editor) { - if (category == null) { - throw new NullArgumentException("category"); - } - - if (key == null) { - throw new NullArgumentException("key"); - } - - if (editor == null) { - editor = new StringPropertyEditor(); - } - - this.category = category; - this.key = key; - this.icon = icon; - this.editor = editor; - } - - /** - * @return the key - */ - public String getKey() { - return key; - } - - /** - * @return the category - */ - public PropertyCategory getCategory() { - return category; - } - - /** - * @return the editor - */ - public PropertyEditor getEditor() { - return editor; - } - - /** - * @return the icon - */ - public String getIcon() { - return icon; - } - - /** - * @param icon - * the icon to set - */ - public void setIcon(String icon) { - this.icon = icon; - } - - /** - * @param context - * @return - */ - public String getName(FacesContext context) { - if (context == null) { - throw new NullArgumentException("context"); - } - - ResourceBundle bundle = context.getApplication().getResourceBundle( - context, "msg"); - return bundle.getString("properties." + key); - } - - /** - * @param context - * @return - */ - public String getDescription(FacesContext context) { - if (context == null) { - throw new NullArgumentException("context"); - } - - ResourceBundle bundle = context.getApplication().getResourceBundle( - context, "msg"); - return bundle.getString("properties." + key + ".description"); - } +public class PropertyDescriptor implements Serializable { + + private String key; + + private PropertyCategory category; + + private String icon; + + private PropertyEditor editor; + + /** + * @param category + * @param key + * @param icon + * @param editor + */ + public PropertyDescriptor(PropertyCategory category, String key, + String icon, PropertyEditor editor) { + if (category == null) { + throw new NullArgumentException("category"); + } + + if (key == null) { + throw new NullArgumentException("key"); + } + + if (editor == null) { + editor = new StringPropertyEditor(); + } + + this.category = category; + this.key = key; + this.icon = icon; + this.editor = editor; + } + + /** + * @return the key + */ + public String getKey() { + return key; + } + + /** + * @return the category + */ + public PropertyCategory getCategory() { + return category; + } + + /** + * @return the editor + */ + public PropertyEditor getEditor() { + return editor; + } + + /** + * @return the icon + */ + public String getIcon() { + return icon; + } + + /** + * @param icon the icon to set + */ + public void setIcon(String icon) { + this.icon = icon; + } + + /** + * @param context + * @return + */ + public String getName(FacesContext context) { + if (context == null) { + throw new NullArgumentException("context"); + } + + ResourceBundle bundle = context.getApplication().getResourceBundle( + context, "msg"); + return bundle.getString("properties." + key); + } + + /** + * @param context + * @return + */ + public String getDescription(FacesContext context) { + if (context == null) { + throw new NullArgumentException("context"); + } + + ResourceBundle bundle = context.getApplication().getResourceBundle( + context, "msg"); + return bundle.getString("properties." + key + ".description"); + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/PropertyDescriptorFactory.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/PropertyDescriptorFactory.java index 6b9b2d2b..82e21a35 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/PropertyDescriptorFactory.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/PropertyDescriptorFactory.java @@ -1,5 +1,6 @@ package org.pivot4j.analytics.property; +import java.io.Serializable; import java.util.HashMap; import java.util.Map; @@ -11,87 +12,87 @@ @ManagedBean(name = "propertyDescriptorFactory") @ApplicationScoped -public class PropertyDescriptorFactory { - - private Map cellProperties; - - private Map headerProperties; - - @PostConstruct - protected void initialize() { - this.cellProperties = new HashMap(); - this.headerProperties = new HashMap(); - - populateProperties(PropertyCategory.Cell); - populateProperties(PropertyCategory.Header); - } - - /** - * @param category - */ - protected void populateProperties(PropertyCategory category) { - Map properties = getDescriptors(category); - - properties.put("label", new PropertyDescriptor(category, "label", - "ui-icon-info", new StringPropertyEditor())); - properties.put("link", new PropertyDescriptor(category, "link", - "ui-icon-link", new StringPropertyEditor(40))); - properties.put("styleClass", new PropertyDescriptor(category, - "styleClass", "ui-icon-tag", new StringPropertyEditor(30))); - properties.put("fgColor", new PropertyDescriptor(category, "fgColor", - "ui-icon-image", new ColorPropertyEditor())); - properties.put("bgColor", new PropertyDescriptor(category, "bgColor", - "ui-icon-image", new ColorPropertyEditor())); - properties - .put("fontFamily", new PropertyDescriptor(category, - "fontFamily", "ui-icon-pencil", - new FontFamilyPropertyEditor())); - properties.put("fontSize", new PropertyDescriptor(category, "fontSize", - "ui-icon-pencil", new FontSizePropertyEditor())); - properties.put("fontStyle", - new PropertyDescriptor(category, "fontStyle", "ui-icon-pencil", - new FontStylePropertyEditor())); - } - - /** - * @param category - * @param key - * @return - */ - public PropertyDescriptor getDescriptor(PropertyCategory category, - String key) { - if (key == null) { - throw new NullArgumentException("key"); - } - - Map properties = getDescriptors(category); - - return properties.get(key); - } - - /** - * @param category - * @return - */ - protected Map getDescriptors( - PropertyCategory category) { - if (category == null) { - throw new NullArgumentException("category"); - } - - Map properties = null; - - switch (category) { - case Cell: - properties = cellProperties; - break; - case Header: - properties = headerProperties; - break; - default: - assert false; - } - - return properties; - } +public class PropertyDescriptorFactory implements Serializable { + + private Map cellProperties; + + private Map headerProperties; + + @PostConstruct + protected void initialize() { + this.cellProperties = new HashMap(); + this.headerProperties = new HashMap(); + + populateProperties(PropertyCategory.Cell); + populateProperties(PropertyCategory.Header); + } + + /** + * @param category + */ + protected void populateProperties(PropertyCategory category) { + Map properties = getDescriptors(category); + + properties.put("label", new PropertyDescriptor(category, "label", + "ui-icon-info", new StringPropertyEditor())); + properties.put("link", new PropertyDescriptor(category, "link", + "ui-icon-link", new StringPropertyEditor(40))); + properties.put("styleClass", new PropertyDescriptor(category, + "styleClass", "ui-icon-tag", new StringPropertyEditor(30))); + properties.put("fgColor", new PropertyDescriptor(category, "fgColor", + "ui-icon-image", new ColorPropertyEditor())); + properties.put("bgColor", new PropertyDescriptor(category, "bgColor", + "ui-icon-image", new ColorPropertyEditor())); + properties + .put("fontFamily", new PropertyDescriptor(category, + "fontFamily", "ui-icon-pencil", + new FontFamilyPropertyEditor())); + properties.put("fontSize", new PropertyDescriptor(category, "fontSize", + "ui-icon-pencil", new FontSizePropertyEditor())); + properties.put("fontStyle", + new PropertyDescriptor(category, "fontStyle", "ui-icon-pencil", + new FontStylePropertyEditor())); + } + + /** + * @param category + * @param key + * @return + */ + public PropertyDescriptor getDescriptor(PropertyCategory category, + String key) { + if (key == null) { + throw new NullArgumentException("key"); + } + + Map properties = getDescriptors(category); + + return properties.get(key); + } + + /** + * @param category + * @return + */ + protected Map getDescriptors( + PropertyCategory category) { + if (category == null) { + throw new NullArgumentException("category"); + } + + Map properties = null; + + switch (category) { + case Cell: + properties = cellProperties; + break; + case Header: + properties = headerProperties; + break; + default: + assert false; + } + + return properties; + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/PropertyEditor.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/PropertyEditor.java index 56276fb0..d0d692a5 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/PropertyEditor.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/PropertyEditor.java @@ -8,28 +8,28 @@ public interface PropertyEditor { - /** - * @param descriptor - * @param parent - * @param expression - * @param listener - * @param update - */ - void createComponent(PropertyDescriptor descriptor, UIComponent parent, - ValueExpression expression, MethodExpression listener, String update); + /** + * @param descriptor + * @param parent + * @param expression + * @param listener + * @param update + */ + void createComponent(PropertyDescriptor descriptor, UIComponent parent, + ValueExpression expression, MethodExpression listener, String update); - /** - * @param descriptor - * @param properties - * @return - */ - Object getValue(PropertyDescriptor descriptor, RenderPropertyList properties); + /** + * @param descriptor + * @param properties + * @return + */ + Object getValue(PropertyDescriptor descriptor, RenderPropertyList properties); - /** - * @param descriptor - * @param properties - * @param value - */ - void setValue(PropertyDescriptor descriptor, RenderPropertyList properties, - Object value); + /** + * @param descriptor + * @param properties + * @param value + */ + void setValue(PropertyDescriptor descriptor, RenderPropertyList properties, + Object value); } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/SelectStringPropertyEditor.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/SelectStringPropertyEditor.java index 0ee86f8e..5aab4cf3 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/SelectStringPropertyEditor.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/SelectStringPropertyEditor.java @@ -12,51 +12,51 @@ public class SelectStringPropertyEditor extends AbstractPropertyInputEditor { - private List items; - - public SelectStringPropertyEditor() { - } - - /** - * @param items - */ - public SelectStringPropertyEditor(List items) { - this.items = items; - } - - /** - * @return the items - */ - public List getItems() { - return items; - } - - /** - * @param items - * the items to set - */ - public void setItems(List items) { - this.items = items; - } - - /** - * @see org.pivot4j.analytics.property.AbstractPropertyInputEditor#createInput(org.pivot4j.analytics.property.PropertyDescriptor, - * javax.faces.component.UIComponent, javax.faces.context.FacesContext) - */ - @Override - protected UIInput createInput(PropertyDescriptor descriptor, - UIComponent parent, FacesContext context) { - Application application = FacesContext.getCurrentInstance() - .getApplication(); - SelectOneMenu select = (SelectOneMenu) application - .createComponent(SelectOneMenu.COMPONENT_TYPE); - - if (items != null) { - for (UISelectItem item : items) { - select.getChildren().add(item); - } - } - - return select; - } + private List items; + + public SelectStringPropertyEditor() { + } + + /** + * @param items + */ + public SelectStringPropertyEditor(List items) { + this.items = items; + } + + /** + * @return the items + */ + public List getItems() { + return items; + } + + /** + * @param items the items to set + */ + public void setItems(List items) { + this.items = items; + } + + /** + * @see + * org.pivot4j.analytics.property.AbstractPropertyInputEditor#createInput(org.pivot4j.analytics.property.PropertyDescriptor, + * javax.faces.component.UIComponent, javax.faces.context.FacesContext) + */ + @Override + protected UIInput createInput(PropertyDescriptor descriptor, + UIComponent parent, FacesContext context) { + Application application = FacesContext.getCurrentInstance() + .getApplication(); + SelectOneMenu select = (SelectOneMenu) application + .createComponent(SelectOneMenu.COMPONENT_TYPE); + + if (items != null) { + for (UISelectItem item : items) { + select.getChildren().add(item); + } + } + + return select; + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/StringPropertyEditor.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/StringPropertyEditor.java index 8c3ff610..093e6178 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/StringPropertyEditor.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/property/StringPropertyEditor.java @@ -9,51 +9,51 @@ public class StringPropertyEditor extends AbstractPropertyInputEditor { - private Integer size; - - public StringPropertyEditor() { - } - - /** - * @param size - */ - public StringPropertyEditor(Integer size) { - this.size = size; - } - - /** - * @see org.pivot4j.analytics.property.AbstractPropertyInputEditor#createInput - * (org.pivot4j.analytics.property.PropertyDescriptor, - * javax.faces.component.UIComponent, javax.faces.context.FacesContext) - */ - @Override - protected UIInput createInput(PropertyDescriptor descriptor, - UIComponent parent, FacesContext context) { - Application application = FacesContext.getCurrentInstance() - .getApplication(); - - InputText input = (InputText) application - .createComponent(InputText.COMPONENT_TYPE); - - if (size != null) { - input.setSize(size); - } - - return input; - } - - /** - * @return the size - */ - public Integer getSize() { - return size; - } - - /** - * @param size - * the size to set - */ - public void setSize(Integer size) { - this.size = size; - } + private Integer size; + + public StringPropertyEditor() { + } + + /** + * @param size + */ + public StringPropertyEditor(Integer size) { + this.size = size; + } + + /** + * @see + * org.pivot4j.analytics.property.AbstractPropertyInputEditor#createInput + * (org.pivot4j.analytics.property.PropertyDescriptor, + * javax.faces.component.UIComponent, javax.faces.context.FacesContext) + */ + @Override + protected UIInput createInput(PropertyDescriptor descriptor, + UIComponent parent, FacesContext context) { + Application application = FacesContext.getCurrentInstance() + .getApplication(); + + InputText input = (InputText) application + .createComponent(InputText.COMPONENT_TYPE); + + if (size != null) { + input.setSize(size); + } + + return input; + } + + /** + * @return the size + */ + public Integer getSize() { + return size; + } + + /** + * @param size the size to set + */ + public void setSize(Integer size) { + this.size = size; + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/AbstractFileSystemRepository.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/AbstractFileSystemRepository.java index b2e649af..700d40fc 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/AbstractFileSystemRepository.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/AbstractFileSystemRepository.java @@ -11,56 +11,58 @@ public abstract class AbstractFileSystemRepository implements ReportRepository { - /** - * @see org.pivot4j.analytics.repository.ReportRepository#getFiles(org.pivot4j.analytics.repository.ReportFile, - * org.pivot4j.analytics.repository.RepositoryFileFilter) - */ - @Override - public List getFiles(ReportFile parent, - RepositoryFileFilter filter) throws IOException { - List files = getFiles(parent); + /** + * @see + * org.pivot4j.analytics.repository.ReportRepository#getFiles(org.pivot4j.analytics.repository.ReportFile, + * org.pivot4j.analytics.repository.RepositoryFileFilter) + */ + @Override + public List getFiles(ReportFile parent, + RepositoryFileFilter filter) throws IOException { + List files = getFiles(parent); - List result; + List result; - if (filter == null) { - result = files; - } else { - result = new LinkedList(); + if (filter == null) { + result = files; + } else { + result = new LinkedList(); - for (ReportFile file : files) { - if (filter.accept(file)) { - result.add(file); - } - } - } + for (ReportFile file : files) { + if (filter.accept(file)) { + result.add(file); + } + } + } - return result; - } + return result; + } - /** - * @throws IOException - * @throws ConfigurationException - * @see org.pivot4j.analytics.repository.ReportRepository#getReportContent(org.pivot4j.analytics.repository.ReportFile) - */ - @Override - public ReportContent getReportContent(ReportFile file) - throws IOException, ConfigurationException { - if (file == null) { - throw new NullArgumentException("file"); - } + /** + * @throws IOException + * @throws ConfigurationException + * @see + * org.pivot4j.analytics.repository.ReportRepository#getReportContent(org.pivot4j.analytics.repository.ReportFile) + */ + @Override + public ReportContent getReportContent(ReportFile file) + throws IOException, ConfigurationException { + if (file == null) { + throw new NullArgumentException("file"); + } - ReportContent content = null; + ReportContent content = null; - InputStream in = null; + InputStream in = null; - try { - in = readContent(file); + try { + in = readContent(file); - content = new ReportContent(in); - } catch (IOException e) { - IOUtils.closeQuietly(in); - } + content = new ReportContent(in); + } catch (IOException e) { + IOUtils.closeQuietly(in); + } - return content; - } + return content; + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/AbstractReportFile.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/AbstractReportFile.java index 6e4bace7..2125fe1a 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/AbstractReportFile.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/AbstractReportFile.java @@ -11,86 +11,86 @@ public abstract class AbstractReportFile implements ReportFile { - /** - * @see org.pivot4j.analytics.repository.ReportFile#getId() - */ - @Override - public Serializable getId() { - return getPath(); - } - - /** - * @see org.pivot4j.analytics.repository.ReportFile#getAncestors() - */ - @Override - public List getAncestors() throws IOException { - List ancestors = new ArrayList(); - - ReportFile parent = this; - - while ((parent = parent.getParent()) != null) { - ancestors.add(parent); - } - - return ancestors; - } - - /** - * @see org.pivot4j.analytics.repository.ReportFile#isRoot() - */ - @Override - public boolean isRoot() { - try { - return getParent() == null; - } catch (IOException e) { - throw new UnhandledException(e); - } - } - - /** - * @see org.pivot4j.analytics.repository.ReportFile#getExtension() - */ - @Override - public String getExtension() { - String name = getName(); - - int index = name.lastIndexOf('.'); - - if (index != -1) { - return name.substring(index + 1); - } - - return null; - } - - /** - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - return new HashCodeBuilder().append(getPath()).build(); - } - - /** - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(Object obj) { - if (!(obj instanceof ReportFile)) { - return false; - } - - ReportFile other = (ReportFile) obj; - - return new EqualsBuilder().append(getClass(), other.getClass()) - .append(getPath(), other.getPath()).build(); - } - - /** - * @see java.lang.Object#toString() - */ - @Override - public String toString() { - return getPath(); - } + /** + * @see org.pivot4j.analytics.repository.ReportFile#getId() + */ + @Override + public Serializable getId() { + return getPath(); + } + + /** + * @see org.pivot4j.analytics.repository.ReportFile#getAncestors() + */ + @Override + public List getAncestors() throws IOException { + List ancestors = new ArrayList(); + + ReportFile parent = this; + + while ((parent = parent.getParent()) != null) { + ancestors.add(parent); + } + + return ancestors; + } + + /** + * @see org.pivot4j.analytics.repository.ReportFile#isRoot() + */ + @Override + public boolean isRoot() { + try { + return getParent() == null; + } catch (IOException e) { + throw new UnhandledException(e); + } + } + + /** + * @see org.pivot4j.analytics.repository.ReportFile#getExtension() + */ + @Override + public String getExtension() { + String name = getName(); + + int index = name.lastIndexOf('.'); + + if (index != -1) { + return name.substring(index + 1); + } + + return null; + } + + /** + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + return new HashCodeBuilder().append(getPath()).build(); + } + + /** + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (!(obj instanceof ReportFile)) { + return false; + } + + ReportFile other = (ReportFile) obj; + + return new EqualsBuilder().append(getClass(), other.getClass()) + .append(getPath(), other.getPath()).build(); + } + + /** + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return getPath(); + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/DataSourceNotFoundException.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/DataSourceNotFoundException.java index 81abac7a..84525fe1 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/DataSourceNotFoundException.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/DataSourceNotFoundException.java @@ -4,21 +4,21 @@ public class DataSourceNotFoundException extends Exception { - private static final long serialVersionUID = -6634494832895522425L; - - private ConnectionInfo connectionInfo; + private static final long serialVersionUID = -6634494832895522425L; - /** - * @param connectionInfo - */ - public DataSourceNotFoundException(ConnectionInfo connectionInfo) { - this.connectionInfo = connectionInfo; - } + private ConnectionInfo connectionInfo; - /** - * @return the connectionInfo - */ - public ConnectionInfo getConnectionInfo() { - return connectionInfo; - } + /** + * @param connectionInfo + */ + public DataSourceNotFoundException(ConnectionInfo connectionInfo) { + this.connectionInfo = connectionInfo; + } + + /** + * @return the connectionInfo + */ + public ConnectionInfo getConnectionInfo() { + return connectionInfo; + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/ReportContent.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/ReportContent.java index bf5071d4..9f5d26d5 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/ReportContent.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/ReportContent.java @@ -32,251 +32,251 @@ public class ReportContent implements Serializable { - private static final long serialVersionUID = 8261947657917338352L; + private static final long serialVersionUID = 8261947657917338352L; - private transient HierarchicalConfiguration configuration; + private transient HierarchicalConfiguration configuration; - /** - * @param state - */ - public ReportContent(ViewState state) { - if (state == null) { - throw new NullArgumentException("state"); - } + /** + * @param state + */ + public ReportContent(ViewState state) { + if (state == null) { + throw new NullArgumentException("state"); + } - this.configuration = createConfiguration(); + this.configuration = createConfiguration(); - ConnectionInfo connectionInfo = state.getConnectionInfo(); + ConnectionInfo connectionInfo = state.getConnectionInfo(); - if (connectionInfo != null) { - configuration.addProperty("connection", ""); - connectionInfo.saveSettings(configuration.configurationAt( - "connection", true)); - } + if (connectionInfo != null) { + configuration.addProperty("connection", ""); + connectionInfo.saveSettings(configuration.configurationAt( + "connection", true)); + } - PivotModel model = state.getModel(); - if (model != null) { - configuration.addProperty("model", ""); - model.saveSettings(configuration.configurationAt("model", true)); - } - - if (state.getRendererState() != null) { - DefaultTableRenderer renderer = new DefaultTableRenderer(); - - renderer.restoreState(state.getRendererState()); - - configuration.addProperty("render", ""); - renderer.saveSettings(configuration.configurationAt("render")); - } - - if (state.getChartState() != null) { - DefaultChartRenderer renderer = new DefaultChartRenderer(); - - renderer.restoreState(state.getChartState()); - - configuration.addProperty("chart", ""); - renderer.saveSettings(configuration.configurationAt("chart")); - } - - Map regions = state.getLayoutRegions(); - - configuration.addProperty("views", ""); - - HierarchicalConfiguration views = configuration.configurationAt( - "views", true); - - int index = 0; - - MessageFormat mf = new MessageFormat("view({0})[@{1}]"); - - for (LayoutRegion region : regions.keySet()) { - Boolean visibility = regions.get(region); - - if (visibility == null) { - visibility = false; - } - - views.addProperty( - mf.format(new String[] { Integer.toString(index), "name" }), - region.name()); - views.addProperty(mf.format(new String[] { Integer.toString(index), - "visible" }), visibility.toString()); + PivotModel model = state.getModel(); + if (model != null) { + configuration.addProperty("model", ""); + model.saveSettings(configuration.configurationAt("model", true)); + } + + if (state.getRendererState() != null) { + DefaultTableRenderer renderer = new DefaultTableRenderer(); + + renderer.restoreState(state.getRendererState()); + + configuration.addProperty("render", ""); + renderer.saveSettings(configuration.configurationAt("render")); + } + + if (state.getChartState() != null) { + DefaultChartRenderer renderer = new DefaultChartRenderer(); + + renderer.restoreState(state.getChartState()); + + configuration.addProperty("chart", ""); + renderer.saveSettings(configuration.configurationAt("chart")); + } + + Map regions = state.getLayoutRegions(); + + configuration.addProperty("views", ""); + + HierarchicalConfiguration views = configuration.configurationAt( + "views", true); + + int index = 0; + + MessageFormat mf = new MessageFormat("view({0})[@{1}]"); + + for (LayoutRegion region : regions.keySet()) { + Boolean visibility = regions.get(region); + + if (visibility == null) { + visibility = false; + } + + views.addProperty( + mf.format(new String[]{Integer.toString(index), "name"}), + region.name()); + views.addProperty(mf.format(new String[]{Integer.toString(index), + "visible"}), visibility.toString()); - index++; - } - } + index++; + } + } - /** - * @param in - * @throws ConfigurationException - */ - public ReportContent(InputStream in) throws IOException, - ConfigurationException { - if (in == null) { - throw new NullArgumentException("in"); - } + /** + * @param in + * @throws ConfigurationException + */ + public ReportContent(InputStream in) throws IOException, + ConfigurationException { + if (in == null) { + throw new NullArgumentException("in"); + } - FileConfiguration config = (FileConfiguration) createConfiguration(); - config.load(new InputStreamReader(in, "UTF-8")); + FileConfiguration config = (FileConfiguration) createConfiguration(); + config.load(new InputStreamReader(in, "UTF-8")); - this.configuration = (HierarchicalConfiguration) config; - } + this.configuration = (HierarchicalConfiguration) config; + } - /** - * Constructor used in serialization. - */ - ReportContent() { - } + /** + * Constructor used in serialization. + */ + ReportContent() { + } - /** - * @param out - * @throws ConfigurationException - */ - public void write(OutputStream out) throws IOException, - ConfigurationException { - if (out == null) { - throw new NullArgumentException("out"); - } + /** + * @param out + * @throws ConfigurationException + */ + public void write(OutputStream out) throws IOException, + ConfigurationException { + if (out == null) { + throw new NullArgumentException("out"); + } - FileConfiguration config = (FileConfiguration) this.configuration; - config.save(new OutputStreamWriter(out, "UTF-8")); - } + FileConfiguration config = (FileConfiguration) this.configuration; + config.save(new OutputStreamWriter(out, "UTF-8")); + } - /** - * @return the configuration - */ - protected HierarchicalConfiguration createConfiguration() { - XMLConfiguration config = new XMLConfiguration(); + /** + * @return the configuration + */ + protected HierarchicalConfiguration createConfiguration() { + XMLConfiguration config = new XMLConfiguration(); - config.setRootElementName("report"); - config.setDelimiterParsingDisabled(true); + config.setRootElementName("report"); + config.setDelimiterParsingDisabled(true); - return config; - } + return config; + } - /** - * @param state - * @param manager - * @param defaultSettings - * @return - * @throws ConfigurationException - * @throws DataSourceNotFoundException - */ - public ViewState read(ViewState state, DataSourceManager manager, - HierarchicalConfiguration defaultSettings) - throws ConfigurationException, DataSourceNotFoundException { - if (state == null) { - throw new NullArgumentException("state"); - } + /** + * @param state + * @param manager + * @param defaultSettings + * @return + * @throws ConfigurationException + * @throws DataSourceNotFoundException + */ + public ViewState read(ViewState state, DataSourceManager manager, + HierarchicalConfiguration defaultSettings) + throws ConfigurationException, DataSourceNotFoundException { + if (state == null) { + throw new NullArgumentException("state"); + } - if (manager == null) { - throw new NullArgumentException("manager"); - } + if (manager == null) { + throw new NullArgumentException("manager"); + } - ConnectionInfo connectionInfo = new ConnectionInfo(); + ConnectionInfo connectionInfo = new ConnectionInfo(); - try { - connectionInfo.restoreSettings(configuration - .configurationAt("connection")); - } catch (IllegalArgumentException e) { - } - - state.setConnectionInfo(connectionInfo); - - OlapDataSource dataSource = manager.getDataSource(connectionInfo); - - if (dataSource == null) { - throw new DataSourceNotFoundException(connectionInfo); - } - - CombinedConfiguration mergedSettings = new CombinedConfiguration(); - mergedSettings.setNodeCombiner(new MergeCombiner()); - - if (defaultSettings != null) { - mergedSettings.addConfiguration(defaultSettings); - } - - mergedSettings.addConfiguration(configuration); - - PivotModel model = new PivotModelImpl(dataSource); - - try { - model.restoreSettings(mergedSettings.configurationAt("model")); - } catch (IllegalArgumentException e) { - e.printStackTrace(); - } - - Map parameters = state.getParameters(); - - if (parameters == null) { - parameters = Collections.emptyMap(); - } - - model.getExpressionContext().put("parameters", parameters); - - state.setModel(model); - - try { - DefaultTableRenderer renderer = new DefaultTableRenderer(); - - renderer.restoreSettings(mergedSettings.configurationAt("render")); - - state.setRendererState(renderer.saveState()); - } catch (IllegalArgumentException e) { - } - - try { - DefaultChartRenderer renderer = new DefaultChartRenderer(); - renderer.restoreSettings(configuration.configurationAt("chart")); - - state.setChartState(renderer.saveState()); - } catch (IllegalArgumentException e) { - } + try { + connectionInfo.restoreSettings(configuration + .configurationAt("connection")); + } catch (IllegalArgumentException e) { + } + + state.setConnectionInfo(connectionInfo); + + OlapDataSource dataSource = manager.getDataSource(connectionInfo); + + if (dataSource == null) { + throw new DataSourceNotFoundException(connectionInfo); + } + + CombinedConfiguration mergedSettings = new CombinedConfiguration(); + mergedSettings.setNodeCombiner(new MergeCombiner()); + + if (defaultSettings != null) { + mergedSettings.addConfiguration(defaultSettings); + } + + mergedSettings.addConfiguration(configuration); + + PivotModel model = new PivotModelImpl(dataSource); + + try { + model.restoreSettings(mergedSettings.configurationAt("model")); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } + + Map parameters = state.getParameters(); + + if (parameters == null) { + parameters = Collections.emptyMap(); + } + + model.getExpressionContext().put("parameters", parameters); + + state.setModel(model); + + try { + DefaultTableRenderer renderer = new DefaultTableRenderer(); + + renderer.restoreSettings(mergedSettings.configurationAt("render")); + + state.setRendererState(renderer.saveState()); + } catch (IllegalArgumentException e) { + } + + try { + DefaultChartRenderer renderer = new DefaultChartRenderer(); + renderer.restoreSettings(configuration.configurationAt("chart")); + + state.setChartState(renderer.saveState()); + } catch (IllegalArgumentException e) { + } - state.getLayoutRegions().clear(); + state.getLayoutRegions().clear(); - List views = configuration - .configurationsAt("views.view"); + List views = configuration + .configurationsAt("views.view"); - for (HierarchicalConfiguration view : views) { - LayoutRegion region = LayoutRegion.valueOf(view - .getString("[@name]")); + for (HierarchicalConfiguration view : views) { + LayoutRegion region = LayoutRegion.valueOf(view + .getString("[@name]")); - boolean visibility = view.getBoolean("[@visible]", true); + boolean visibility = view.getBoolean("[@visible]", true); - state.setRegionVisible(region, visibility); - } + state.setRegionVisible(region, visibility); + } - return state; - } + return state; + } - /** - * @param in - * @throws IOException - */ - private void readObject(ObjectInputStream in) throws IOException { - this.configuration = createConfiguration(); + /** + * @param in + * @throws IOException + */ + private void readObject(ObjectInputStream in) throws IOException { + this.configuration = createConfiguration(); - FileConfiguration fileConfig = (FileConfiguration) configuration; + FileConfiguration fileConfig = (FileConfiguration) configuration; - try { - fileConfig.load(in); - } catch (ConfigurationException e) { - throw new IOException(e); - } - } + try { + fileConfig.load(in); + } catch (ConfigurationException e) { + throw new IOException(e); + } + } - /** - * @param out - * @throws IOException - */ - private void writeObject(ObjectOutputStream out) throws IOException { - FileConfiguration fileConfig = (FileConfiguration) configuration; + /** + * @param out + * @throws IOException + */ + private void writeObject(ObjectOutputStream out) throws IOException { + FileConfiguration fileConfig = (FileConfiguration) configuration; - try { - fileConfig.save(out); - } catch (ConfigurationException e) { - throw new IOException(e); - } - } + try { + fileConfig.save(out); + } catch (ConfigurationException e) { + throw new IOException(e); + } + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/ReportFile.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/ReportFile.java index 795a84a5..ead73e7b 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/ReportFile.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/ReportFile.java @@ -7,29 +7,29 @@ public interface ReportFile { - String SEPARATOR = "/"; + String SEPARATOR = "/"; - Serializable getId(); + Serializable getId(); - String getName(); + String getName(); - String getPath(); + String getPath(); - String getExtension(); + String getExtension(); - ReportFile getParent() throws IOException; + ReportFile getParent() throws IOException; - List getAncestors() throws IOException; + List getAncestors() throws IOException; - boolean isDirectory(); + boolean isDirectory(); - boolean isRoot(); - - Date getLastModifiedDate(); - - long getSize(); + boolean isRoot(); - boolean canRead(); + Date getLastModifiedDate(); - boolean canWrite(); + long getSize(); + + boolean canRead(); + + boolean canWrite(); } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/ReportRepository.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/ReportRepository.java index 177560f1..a3a970c6 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/ReportRepository.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/ReportRepository.java @@ -8,36 +8,36 @@ public interface ReportRepository { - ReportFile getRoot() throws IOException; + ReportFile getRoot() throws IOException; - ReportFile getFile(String path) throws IOException; + ReportFile getFile(String path) throws IOException; - ReportFile getFileById(String id) throws IOException; + ReportFile getFileById(String id) throws IOException; - boolean exists(String path) throws IOException; + boolean exists(String path) throws IOException; - boolean fileWithIdExists(String id) throws IOException; + boolean fileWithIdExists(String id) throws IOException; - List getFiles(ReportFile parent) throws IOException; + List getFiles(ReportFile parent) throws IOException; - List getFiles(ReportFile parent, RepositoryFileFilter filter) - throws IOException; + List getFiles(ReportFile parent, RepositoryFileFilter filter) + throws IOException; - ReportFile createDirectory(ReportFile parent, String name) - throws IOException; + ReportFile createDirectory(ReportFile parent, String name) + throws IOException; - ReportFile createFile(ReportFile parent, String name, ReportContent content) - throws IOException, ConfigurationException; + ReportFile createFile(ReportFile parent, String name, ReportContent content) + throws IOException, ConfigurationException; - ReportFile renameFile(ReportFile file, String newName) throws IOException; + ReportFile renameFile(ReportFile file, String newName) throws IOException; - void deleteFile(ReportFile file) throws IOException; + void deleteFile(ReportFile file) throws IOException; - ReportContent getReportContent(ReportFile file) throws IOException, - ConfigurationException; + ReportContent getReportContent(ReportFile file) throws IOException, + ConfigurationException; - void setReportContent(ReportFile file, ReportContent content) - throws IOException, ConfigurationException; + void setReportContent(ReportFile file, ReportContent content) + throws IOException, ConfigurationException; - InputStream readContent(ReportFile file) throws IOException; + InputStream readContent(ReportFile file) throws IOException; } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/RepositoryFileComparator.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/RepositoryFileComparator.java index 906ba56e..274b9f44 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/RepositoryFileComparator.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/RepositoryFileComparator.java @@ -4,31 +4,31 @@ public class RepositoryFileComparator implements Comparator { - /** - * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) - */ - @Override - public int compare(ReportFile f1, ReportFile f2) { - int result = 0; + /** + * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) + */ + @Override + public int compare(ReportFile f1, ReportFile f2) { + int result = 0; - if (f1 == null) { - if (f2 != null) { - result = 1; - } - } else if (f2 != null) { - if (f1.isDirectory()) { - if (f2.isDirectory()) { - result = f1.getPath().compareTo(f2.getPath()); - } else { - result = -1; - } - } else if (f2.isDirectory()) { - result = 1; - } else { - result = f1.getPath().compareTo(f2.getPath()); - } - } + if (f1 == null) { + if (f2 != null) { + result = 1; + } + } else if (f2 != null) { + if (f1.isDirectory()) { + if (f2.isDirectory()) { + result = f1.getPath().compareTo(f2.getPath()); + } else { + result = -1; + } + } else if (f2.isDirectory()) { + result = 1; + } else { + result = f1.getPath().compareTo(f2.getPath()); + } + } - return result; - } + return result; + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/RepositoryFileFilter.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/RepositoryFileFilter.java index b7ba31bc..8b8beaa5 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/RepositoryFileFilter.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/RepositoryFileFilter.java @@ -2,9 +2,9 @@ public interface RepositoryFileFilter { - /** - * @param file - * @return - */ - boolean accept(ReportFile file); + /** + * @param file + * @return + */ + boolean accept(ReportFile file); } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/file/LocalFile.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/file/LocalFile.java index 70d3675c..fd6a5587 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/file/LocalFile.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/file/LocalFile.java @@ -2,6 +2,7 @@ import java.io.File; import java.io.IOException; +import java.io.Serializable; import java.util.Date; import org.apache.commons.lang.NullArgumentException; @@ -9,142 +10,142 @@ import org.pivot4j.analytics.repository.AbstractReportFile; import org.pivot4j.analytics.repository.ReportFile; -public class LocalFile extends AbstractReportFile { - - private File root; - - private File file; - - private String path; - - /** - * @param file - * @param root - * @throws IOException - */ - public LocalFile(File file, File root) throws IOException { - if (file == null) { - throw new NullArgumentException("file"); - } - - if (root == null) { - throw new NullArgumentException("root"); - } - - String rootPath = root.getCanonicalPath(); - String filePath = file.getCanonicalPath(); - - if (!filePath.startsWith(rootPath)) { - throw new IllegalArgumentException( - "The specified file path does not begin with the root path."); - } - - this.file = file; - this.root = root; - - this.path = filePath.substring(rootPath.length()); - - if (path.length() == 0) { - path = SEPARATOR; - } else { - path = StringUtils.replaceChars(path, File.separator, SEPARATOR); - } - } - - /** - * @return the root - */ - protected File getRoot() { - return root; - } - - /** - * @return the file - */ - public File getFile() { - return file; - } - - /** - * @see org.pivot4j.analytics.repository.ReportFile#getName() - */ - @Override - public String getName() { - return file.getName(); - } - - /** - * @see org.pivot4j.analytics.repository.ReportFile#getPath() - */ - @Override - public String getPath() { - return path; - } - - /** - * @throws IOException - * @see org.pivot4j.analytics.repository.ReportFile#getParent() - */ - @Override - public ReportFile getParent() throws IOException { - if (isRoot()) { - return null; - } - - File parent = file.getParentFile(); - - if (parent == null) { - return null; - } - - return new LocalFile(parent, root); - } - - /** - * @see org.pivot4j.analytics.repository.ReportFile#isDirectory() - */ - @Override - public boolean isDirectory() { - return file.isDirectory(); - } - - /** - * @see org.pivot4j.analytics.repository.AbstractReportFile#isRoot() - */ - @Override - public boolean isRoot() { - return root.equals(file); - } - - /** - * @see org.pivot4j.analytics.repository.ReportFile#getLastModifiedDate() - */ - @Override - public Date getLastModifiedDate() { - return new Date(file.lastModified()); - } - - /** - * @see org.pivot4j.analytics.repository.ReportFile#getSize() - */ - @Override - public long getSize() { - return file.length(); - } - - /** - * @see org.pivot4j.analytics.repository.ReportFile#canRead() - */ - @Override - public boolean canRead() { - return file.canRead(); - } - - /** - * @see org.pivot4j.analytics.repository.ReportFile#canWrite() - */ - @Override - public boolean canWrite() { - return file.canWrite(); - } +public class LocalFile extends AbstractReportFile implements Serializable { + + private File root; + + private File file; + + private String path; + + /** + * @param file + * @param root + * @throws IOException + */ + public LocalFile(File file, File root) throws IOException { + if (file == null) { + throw new NullArgumentException("file"); + } + + if (root == null) { + throw new NullArgumentException("root"); + } + + String rootPath = root.getCanonicalPath(); + String filePath = file.getCanonicalPath(); + + if (!filePath.startsWith(rootPath)) { + throw new IllegalArgumentException( + "The specified file path does not begin with the root path."); + } + + this.file = file; + this.root = root; + + this.path = filePath.substring(rootPath.length()); + + if (path.length() == 0) { + path = SEPARATOR; + } else { + path = StringUtils.replaceChars(path, File.separator, SEPARATOR); + } + } + + /** + * @return the root + */ + protected File getRoot() { + return root; + } + + /** + * @return the file + */ + public File getFile() { + return file; + } + + /** + * @see org.pivot4j.analytics.repository.ReportFile#getName() + */ + @Override + public String getName() { + return file.getName(); + } + + /** + * @see org.pivot4j.analytics.repository.ReportFile#getPath() + */ + @Override + public String getPath() { + return path; + } + + /** + * @throws IOException + * @see org.pivot4j.analytics.repository.ReportFile#getParent() + */ + @Override + public ReportFile getParent() throws IOException { + if (isRoot()) { + return null; + } + + File parent = file.getParentFile(); + + if (parent == null) { + return null; + } + + return new LocalFile(parent, root); + } + + /** + * @see org.pivot4j.analytics.repository.ReportFile#isDirectory() + */ + @Override + public boolean isDirectory() { + return file.isDirectory(); + } + + /** + * @see org.pivot4j.analytics.repository.AbstractReportFile#isRoot() + */ + @Override + public boolean isRoot() { + return root.equals(file); + } + + /** + * @see org.pivot4j.analytics.repository.ReportFile#getLastModifiedDate() + */ + @Override + public Date getLastModifiedDate() { + return new Date(file.lastModified()); + } + + /** + * @see org.pivot4j.analytics.repository.ReportFile#getSize() + */ + @Override + public long getSize() { + return file.length(); + } + + /** + * @see org.pivot4j.analytics.repository.ReportFile#canRead() + */ + @Override + public boolean canRead() { + return file.canRead(); + } + + /** + * @see org.pivot4j.analytics.repository.ReportFile#canWrite() + */ + @Override + public boolean canWrite() { + return file.canWrite(); + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/file/LocalFileSystemRepository.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/file/LocalFileSystemRepository.java index 425bce66..6c44ecfb 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/file/LocalFileSystemRepository.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/repository/file/LocalFileSystemRepository.java @@ -7,15 +7,18 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.annotation.PostConstruct; import javax.faces.FacesException; -import javax.faces.bean.ApplicationScoped; import javax.faces.bean.ManagedBean; import javax.faces.bean.ManagedProperty; +import javax.faces.bean.ViewScoped; +import javax.faces.context.FacesContext; +import javax.servlet.http.HttpSession; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.io.FileUtils; @@ -31,328 +34,366 @@ import org.slf4j.LoggerFactory; @ManagedBean(name = "reportRepository") -@ApplicationScoped -public class LocalFileSystemRepository extends AbstractFileSystemRepository { - - @ManagedProperty(value = "#{settings}") - private Settings settings; - - private Logger log = LoggerFactory.getLogger(getClass()); - - private LocalFile root; - - @PostConstruct - protected void initialize() { - String path = getRootPath(); - - if (log.isInfoEnabled()) { - log.info("Root repository path : {}", path); - } - - try { - File file = new File(path); - - if (!file.exists() && !file.mkdirs()) { - throw new IOException( - "Creating repository direcoty failed with unknown reason : " - + path); - } - - this.root = new LocalFile(file, file); - } catch (IOException e) { - throw new FacesException(e); - } - } - - protected String getRootPath() { - File home = settings.getApplicationHome(); - return home.getPath() + File.separator + "repository"; - }; - - /** - * @see org.pivot4j.analytics.repository.ReportRepository#getRoot() - */ - @Override - public ReportFile getRoot() { - return root; - } - - /** - * @see org.pivot4j.analytics.repository.ReportRepository#exists(java.lang.String) - */ - @Override - public boolean exists(String path) throws IOException { - return getSystemFile(path).exists(); - } - - /** - * @see org.pivot4j.analytics.repository.ReportRepository#fileWithIdExists(java.lang.String) - */ - @Override - public boolean fileWithIdExists(String id) throws IOException { - return exists(id); - } - - /** - * @see org.pivot4j.analytics.repository.ReportRepository#getFile(java.lang.String) - */ - @Override - public ReportFile getFile(String path) throws IOException { - File file = getSystemFile(path); - - if (!file.exists()) { - return null; - } - - return new LocalFile(file, root.getRoot()); - } - - /** - * @see org.pivot4j.analytics.repository.ReportRepository#getFileById(java.lang.String) - */ - @Override - public ReportFile getFileById(String id) throws IOException { - return getFile(id); - } - - /** - * @throws IOException - * @see org.pivot4j.analytics.repository.ReportRepository#getFiles(org.pivot4j.analytics.repository.ReportFile) - */ - @Override - public List getFiles(ReportFile parent) throws IOException { - if (parent == null) { - throw new NullArgumentException("parent"); - } - - LocalFile directory = getLocalFile(parent); - - File[] children = directory.getFile().listFiles(); - - if (children == null) { - return Collections.emptyList(); - } - - List files = new ArrayList(children.length); - - for (File child : children) { - files.add(new LocalFile(child, root.getRoot())); - } - - Collections.sort(files, new RepositoryFileComparator()); - - return files; - } - - /** - * @see org.pivot4j.analytics.repository.ReportRepository#createDirectory(org.pivot4j.analytics.repository.ReportFile, - * java.lang.String) - */ - @Override - public ReportFile createDirectory(ReportFile parent, String name) - throws IOException { - if (parent == null) { - throw new NullArgumentException("parent"); - } - - if (name == null) { - throw new NullArgumentException("name"); - } - - LocalFile directory = getLocalFile(parent); - - String path = directory.getFile().getCanonicalPath() + File.separator - + name; - - File file = new File(path); - if (!file.mkdir()) { - throw new IOException( - "Creating a direcoty failed with unknown reason : " + path); - } - - return new LocalFile(file, root.getFile()); - } - - /** - * @throws IOException - * @see org.pivot4j.analytics.repository.ReportRepository#createFile(org.pivot4j.analytics.repository.ReportFile, - * java.lang.String, - * org.pivot4j.analytics.repository.ReportContent) - */ - @Override - public ReportFile createFile(ReportFile parent, String name, - ReportContent content) throws IOException, ConfigurationException { - if (parent == null) { - throw new NullArgumentException("parent"); - } - - if (name == null) { - throw new NullArgumentException("name"); - } - - if (content == null) { - throw new NullArgumentException("content"); - } - - LocalFile directory = getLocalFile(parent); - - String path = directory.getFile().getCanonicalPath() + File.separator - + name; - - File file = new File(path); - - ReportFile localFile = new LocalFile(file, root.getFile()); - - setReportContent(localFile, content); - - return localFile; - } - - /** - * @see org.pivot4j.analytics.repository.ReportRepository#readContent(org.pivot4j.analytics.repository.ReportFile) - */ - @Override - public InputStream readContent(ReportFile file) throws IOException { - if (file == null) { - throw new NullArgumentException("file"); - } - - return new FileInputStream(getLocalFile(file).getFile()); - } - - /** - * @throws ConfigurationException - * @see org.pivot4j.analytics.repository.ReportRepository#setReportContent(org.pivot4j.analytics.repository.ReportFile, - * org.pivot4j.analytics.repository.ReportContent) - */ - @Override - public void setReportContent(ReportFile file, ReportContent content) - throws IOException, ConfigurationException { - if (file == null) { - throw new NullArgumentException("file"); - } - - if (content == null) { - throw new NullArgumentException("content"); - } - - LocalFile localFile = getLocalFile(file); - - OutputStream out = null; - - try { - out = new BufferedOutputStream(new FileOutputStream( - localFile.getFile(), false)); - - content.write(out); - - out.flush(); - } finally { - IOUtils.closeQuietly(out); - } - } - - /** - * @see org.pivot4j.analytics.repository.ReportRepository#renameFile(org.pivot4j.analytics.repository.ReportFile, - * java.lang.String) - */ - @Override - public ReportFile renameFile(ReportFile file, String newName) - throws IOException { - if (file == null) { - throw new NullArgumentException("file"); - } - - if (newName == null) { - throw new NullArgumentException("newName"); - } - - File localFile = getLocalFile(file).getFile(); - - File newFile = new File(localFile.getParent() + File.separator - + newName); - - if (!localFile.renameTo(newFile)) { - throw new IOException( - "Renaming a file failed with unknown reason : " - + newFile.getPath()); - } - - return new LocalFile(newFile, root.getFile()); - } - - /** - * @see org.pivot4j.analytics.repository.ReportRepository#deleteFile(org.pivot4j.analytics.repository.ReportFile) - */ - @Override - public void deleteFile(ReportFile file) throws IOException { - if (file == null) { - throw new NullArgumentException("file"); - } - - File localFile = getLocalFile(file).getFile(); - - if (localFile.isDirectory()) { - FileUtils.deleteDirectory(localFile); - } else { - if (!localFile.delete()) { - throw new IOException( - "Deleting a file failed with unknown reason : " - + localFile.getPath()); - } - } - } - - /** - * @param path - * @return - * @throws IOException - */ - protected File getSystemFile(String path) throws IOException { - if (path == null) { - throw new NullArgumentException("file"); - } - - if (path.equals(ReportFile.SEPARATOR)) { - return root.getFile(); - } - - String filePath = root.getFile().getCanonicalPath() - + StringUtils.replaceChars(path, ReportFile.SEPARATOR, - File.separator); - - return new File(filePath); - } - - /** - * @param file - * @return - * @throws IOException - */ - protected LocalFile getLocalFile(ReportFile file) throws IOException { - LocalFile localFile; - - if (file instanceof LocalFile) { - localFile = (LocalFile) file; - } else { - localFile = (LocalFile) getFile(file.getPath()); - } - - return localFile; - } - - /** - * @return the settings - */ - public Settings getSettings() { - return settings; - } - - /** - * @param settings - * the settings to set - */ - public void setSettings(Settings settings) { - this.settings = settings; - } +@ViewScoped +public class LocalFileSystemRepository extends AbstractFileSystemRepository implements Serializable { + + @ManagedProperty(value = "#{settings}") + private transient Settings settings; + + private Logger log = LoggerFactory.getLogger(getClass()); + + private LocalFile root; + + @PostConstruct + protected void initialize() { + String path = getRootPath(); + + if (log.isInfoEnabled()) { + log.info("Root repository path : {}", path); + } + + try { + File file = new File(path); + + if (!file.exists() && !file.mkdirs()) { + throw new IOException( + "Creating repository direcoty failed with unknown reason : " + + path); + } + + this.root = new LocalFile(file, file); + } catch (IOException e) { + throw new FacesException(e); + } + } + + HttpSession session = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(false); + protected String getRootPath() { + File home = settings.getApplicationHome(); + + try { + if ("client".equals(settings.getAplicationHomePerClient())) { + String client = null; + + try { + if (log.isInfoEnabled()) { + log.info("Trying to get client name from session"); + } + client = (String) session.getAttribute("client"); + } catch (Exception e) { + if (log.isInfoEnabled()) { + log.info("Exception: ", e); + } + } + + if (client == null) { + return home.getPath() + File.separator + "repository"; + } + + return home.getPath() + File.separator + "repository_" + client; + } else { + return home.getPath() + File.separator + "repository"; + } + } catch (Exception e) { + return home.getPath() + File.separator + "repository"; + } + + } + + ; + /** + * @see org.pivot4j.analytics.repository.ReportRepository#getRoot() + */ + @Override + public ReportFile getRoot() { + return root; + } + + /** + * @see + * org.pivot4j.analytics.repository.ReportRepository#exists(java.lang.String) + */ + @Override + public boolean exists(String path) throws IOException { + return getSystemFile(path).exists(); + } + + /** + * @see + * org.pivot4j.analytics.repository.ReportRepository#fileWithIdExists(java.lang.String) + */ + @Override + public boolean fileWithIdExists(String id) throws IOException { + return exists(id); + } + + /** + * @see + * org.pivot4j.analytics.repository.ReportRepository#getFile(java.lang.String) + */ + @Override + public ReportFile getFile(String path) throws IOException { + File file = getSystemFile(path); + + if (!file.exists()) { + return null; + } + + return new LocalFile(file, root.getRoot()); + } + + /** + * @see + * org.pivot4j.analytics.repository.ReportRepository#getFileById(java.lang.String) + */ + @Override + public ReportFile getFileById(String id) throws IOException { + return getFile(id); + } + + /** + * @throws IOException + * @see + * org.pivot4j.analytics.repository.ReportRepository#getFiles(org.pivot4j.analytics.repository.ReportFile) + */ + @Override + public List getFiles(ReportFile parent) throws IOException { + if (parent == null) { + throw new NullArgumentException("parent"); + } + + LocalFile directory = getLocalFile(parent); + + File[] children = directory.getFile().listFiles(); + + if (children == null) { + return Collections.emptyList(); + } + + List files = new ArrayList(children.length); + + for (File child : children) { + files.add(new LocalFile(child, root.getRoot())); + } + + Collections.sort(files, new RepositoryFileComparator()); + + return files; + } + + /** + * @see + * org.pivot4j.analytics.repository.ReportRepository#createDirectory(org.pivot4j.analytics.repository.ReportFile, + * java.lang.String) + */ + @Override + public ReportFile createDirectory(ReportFile parent, String name) + throws IOException { + if (parent == null) { + throw new NullArgumentException("parent"); + } + + if (name == null) { + throw new NullArgumentException("name"); + } + + LocalFile directory = getLocalFile(parent); + + String path = directory.getFile().getCanonicalPath() + File.separator + + name; + + File file = new File(path); + if (!file.mkdir()) { + throw new IOException( + "Creating a direcoty failed with unknown reason : " + path); + } + + return new LocalFile(file, root.getFile()); + } + + /** + * @throws IOException + * @see + * org.pivot4j.analytics.repository.ReportRepository#createFile(org.pivot4j.analytics.repository.ReportFile, + * java.lang.String, org.pivot4j.analytics.repository.ReportContent) + */ + @Override + public ReportFile createFile(ReportFile parent, String name, + ReportContent content) throws IOException, ConfigurationException { + if (parent == null) { + throw new NullArgumentException("parent"); + } + + if (name == null) { + throw new NullArgumentException("name"); + } + + if (content == null) { + throw new NullArgumentException("content"); + } + + LocalFile directory = getLocalFile(parent); + + String path = directory.getFile().getCanonicalPath() + File.separator + + name; + + File file = new File(path); + + ReportFile localFile = new LocalFile(file, root.getFile()); + + setReportContent(localFile, content); + + return localFile; + } + + /** + * @see + * org.pivot4j.analytics.repository.ReportRepository#readContent(org.pivot4j.analytics.repository.ReportFile) + */ + @Override + public InputStream readContent(ReportFile file) throws IOException { + if (file == null) { + throw new NullArgumentException("file"); + } + + return new FileInputStream(getLocalFile(file).getFile()); + } + + /** + * @throws ConfigurationException + * @see + * org.pivot4j.analytics.repository.ReportRepository#setReportContent(org.pivot4j.analytics.repository.ReportFile, + * org.pivot4j.analytics.repository.ReportContent) + */ + @Override + public void setReportContent(ReportFile file, ReportContent content) + throws IOException, ConfigurationException { + if (file == null) { + throw new NullArgumentException("file"); + } + + if (content == null) { + throw new NullArgumentException("content"); + } + + LocalFile localFile = getLocalFile(file); + + OutputStream out = null; + + try { + out = new BufferedOutputStream(new FileOutputStream( + localFile.getFile(), false)); + + content.write(out); + + out.flush(); + } finally { + IOUtils.closeQuietly(out); + } + } + + /** + * @see + * org.pivot4j.analytics.repository.ReportRepository#renameFile(org.pivot4j.analytics.repository.ReportFile, + * java.lang.String) + */ + @Override + public ReportFile renameFile(ReportFile file, String newName) + throws IOException { + if (file == null) { + throw new NullArgumentException("file"); + } + + if (newName == null) { + throw new NullArgumentException("newName"); + } + + File localFile = getLocalFile(file).getFile(); + + File newFile = new File(localFile.getParent() + File.separator + + newName); + + if (!localFile.renameTo(newFile)) { + throw new IOException( + "Renaming a file failed with unknown reason : " + + newFile.getPath()); + } + + return new LocalFile(newFile, root.getFile()); + } + + /** + * @see + * org.pivot4j.analytics.repository.ReportRepository#deleteFile(org.pivot4j.analytics.repository.ReportFile) + */ + @Override + public void deleteFile(ReportFile file) throws IOException { + if (file == null) { + throw new NullArgumentException("file"); + } + + File localFile = getLocalFile(file).getFile(); + + if (localFile.isDirectory()) { + FileUtils.deleteDirectory(localFile); + } else { + if (!localFile.delete()) { + throw new IOException( + "Deleting a file failed with unknown reason : " + + localFile.getPath()); + } + } + } + + /** + * @param path + * @return + * @throws IOException + */ + protected File getSystemFile(String path) throws IOException { + if (path == null) { + throw new NullArgumentException("file"); + } + + if (path.equals(ReportFile.SEPARATOR)) { + return root.getFile(); + } + + String filePath = root.getFile().getCanonicalPath() + + StringUtils.replaceChars(path, ReportFile.SEPARATOR, + File.separator); + + return new File(filePath); + } + + /** + * @param file + * @return + * @throws IOException + */ + protected LocalFile getLocalFile(ReportFile file) throws IOException { + LocalFile localFile; + + if (file instanceof LocalFile) { + localFile = (LocalFile) file; + } else { + localFile = (LocalFile) getFile(file.getPath()); + } + + return localFile; + } + + /** + * @return the settings + */ + public Settings getSettings() { + return settings; + } + + /** + * @param settings the settings to set + */ + public void setSettings(Settings settings) { + this.settings = settings; + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/security/SecurityController.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/security/SecurityController.java new file mode 100644 index 00000000..328cd8a5 --- /dev/null +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/security/SecurityController.java @@ -0,0 +1,38 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.pivot4j.analytics.security; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod;; + +/** + * + * @author Judilson + */ +@Controller +public class SecurityController { + + @RequestMapping(value = "/security/login.xhtml", method = RequestMethod.GET) + public String loginPage() { + return "login"; + } + + @RequestMapping(value = "/security/login.xhtml", method = RequestMethod.GET) + public String logoutPage(HttpServletRequest request, HttpServletResponse response) { + Authentication auth = SecurityContextHolder.getContext().getAuthentication(); + if (auth != null) { + new SecurityContextLogoutHandler().logout(request, response, auth); + } + return "redirect:/security/login.xhtml?logout";//You can redirect wherever you want, but generally it's a good idea to show login screen again. + } +} diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/security/SecurityWebConfig.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/security/SecurityWebConfig.java new file mode 100644 index 00000000..d0edd6ab --- /dev/null +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/security/SecurityWebConfig.java @@ -0,0 +1,69 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.pivot4j.analytics.security; + +import org.springframework.context.annotation.Bean; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; + +/** + * + * @author Judilson + */ +@EnableWebSecurity +public class SecurityWebConfig extends WebSecurityConfigurerAdapter { + + @Override + public void configure(AuthenticationManagerBuilder auth) + throws Exception { + + // in-memory authentication + BCryptPasswordEncoder encoder = passwordEncoder(); + auth.inMemoryAuthentication().withUser("admin").password(encoder.encode("password")).roles("USER"); + // using custom UserDetailsService DAO + // auth.userDetailsService(new AppUserDetailsServiceDAO()); + // using JDBC +// Context ctx = new InitialContext(); +// DataSource ds = (DataSource) ctx +// .lookup("java:/comp/env/jdbc/MyLocalDB"); +// +// final String findUserQuery = "select username,password,enabled " +// + "from Employees " + "where username = ?"; +// final String findRoles = "select username,role " + "from Roles " +// + "where username = ?"; +// +// auth.jdbcAuthentication().dataSource(ds) +// .usersByUsernameQuery(findUserQuery) +// .authoritiesByUsernameQuery(findRoles); + } + + @Bean + public BCryptPasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + + @Override + public void configure(HttpSecurity http) throws Exception { + http + .csrf().disable() + .headers().frameOptions().disable() + .and() + .authorizeRequests() + .antMatchers("/", "/javax.faces.resource/**", "/resource/**", "/home", "/register", "/input", "/output", "/output/*", "/**/*.css", "/**/*.js", "/**/*.png", "/**/*.svg", "/**/*.map", "/**/*.ttf").permitAll() + .anyRequest().authenticated() + .and() + .formLogin() + .loginPage("/security/login.xhtml").permitAll() + .loginProcessingUrl("/Pivot4jLogin") + .failureUrl("/security/login.xhtml?error=true") + .and() + .logout() + .logoutSuccessUrl("/security/login.xhtml"); + } +} diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/security/SpringWebSecurityInitializer.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/security/SpringWebSecurityInitializer.java new file mode 100644 index 00000000..b13f0d8b --- /dev/null +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/security/SpringWebSecurityInitializer.java @@ -0,0 +1,21 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.pivot4j.analytics.security; + +import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer; + +/** + * + * @author Judilson + */ +public class SpringWebSecurityInitializer extends AbstractSecurityWebApplicationInitializer { + + public SpringWebSecurityInitializer() { + super(SecurityWebConfig.class); + } +} + + diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/state/ViewState.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/state/ViewState.java index abeccd77..8cf359b2 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/state/ViewState.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/state/ViewState.java @@ -12,286 +12,286 @@ import org.pivot4j.analytics.repository.ReportFile; import org.pivot4j.analytics.ui.LayoutRegion; -public class ViewState { - - private String id; - - private String name; - - private boolean dirty = false; - - private ReportFile file; - - private boolean readOnly = false; - - private boolean editable = true; - - private Date lastActive = new Date(); - - private ConnectionInfo connectionInfo; - - private PivotModel model; - - private Serializable rendererState; - - private Serializable chartState; - - private Map parameters; - - private Map layoutRegions; - - /** - * @param id - * @param name - */ - public ViewState(String id, String name) { - if (id == null) { - throw new NullArgumentException("id"); - } - - if (name == null) { - throw new NullArgumentException("name"); - } - - this.id = id; - this.name = name; - this.layoutRegions = new HashMap(); - } - - /** - * @param id - * @param name - * @param connectionInfo - * @param model - * @param file - */ - public ViewState(String id, String name, ConnectionInfo connectionInfo, - PivotModel model, ReportFile file) { - if (id == null) { - throw new NullArgumentException("id"); - } - - if (name == null) { - throw new NullArgumentException("name"); - } - - this.id = id; - this.name = name; - this.connectionInfo = connectionInfo; - this.model = model; - this.file = file; - this.layoutRegions = new HashMap(); - } - - /** - * @return the id - */ - public String getId() { - return id; - } - - /** - * @return the name - */ - public String getName() { - return name; - } - - /** - * @param name - * the name to set - */ - public void setName(String name) { - if (name == null) { - throw new NullArgumentException("name"); - } - - this.name = name; - } - - /** - * @return the file - */ - public ReportFile getFile() { - return file; - } - - /** - * @param file - * the file to set - */ - public void setFile(ReportFile file) { - this.file = file; - } - - /** - * @return the lastActive - */ - public Date getLastActive() { - return lastActive; - } - - /** - * @return the connectionInfo - */ - public ConnectionInfo getConnectionInfo() { - return connectionInfo; - } - - /** - * @param connectionInfo - * the connectionInfo to set - */ - public void setConnectionInfo(ConnectionInfo connectionInfo) { - this.connectionInfo = connectionInfo; - } - - /** - * @return the readOnly - */ - public boolean isReadOnly() { - return readOnly; - } - - /** - * @param readOnly - * the readOnly to set - */ - public void setReadOnly(boolean readOnly) { - this.readOnly = readOnly; - } - - /** - * @return the editable - */ - public boolean isEditable() { - return editable; - } - - /** - * @param editable - * the editable to set - */ - public void setEditable(boolean editable) { - this.editable = editable; - } - - /** - * @return the model - */ - public PivotModel getModel() { - return model; - } - - /** - * @param model - * the model to set - */ - public void setModel(PivotModel model) { - this.model = model; - } - - /** - * @return the rendererState - */ - public Serializable getRendererState() { - return rendererState; - } - - /** - * @param rendererState - * the rendererState to set - */ - public void setRendererState(Serializable rendererState) { - this.rendererState = rendererState; - } - - /** - * @return the chartState - */ - public Serializable getChartState() { - return chartState; - } - - /** - * @param chartState - * the chartState to set - */ - public void setChartState(Serializable chartState) { - this.chartState = chartState; - } - - /** - * @return the parameters - */ - public Map getParameters() { - return parameters; - } - - /** - * @param parameters - * the parameters to set - */ - public void setParameters(Map parameters) { - this.parameters = parameters; - } - - /** - * @return the layoutRegions - */ - public Map getLayoutRegions() { - return layoutRegions; - } - - /** - * @param region - * @return - */ - public boolean isRegionVisible(LayoutRegion region) { - if (region == null) { - throw new NullArgumentException("region"); - } - - return !Boolean.FALSE.equals(layoutRegions.get(region)); - } - - /** - * @param region - * @param visible - */ - public void setRegionVisible(LayoutRegion region, boolean visible) { - if (region == null) { - throw new NullArgumentException("region"); - } - - layoutRegions.put(region, visible); - } - - /** - * @return the dirty - */ - public boolean isDirty() { - return dirty; - } - - /** - * @param dirty - * the dirty to set - */ - public void setDirty(boolean dirty) { - this.dirty = dirty; - } - - public void update() { - this.lastActive = new Date(); - } - - /** - * @see java.lang.Object#toString() - */ - @Override - public String toString() { - return new ToStringBuilder(this).append("id", id).append("name", name) - .append("connectionInfo", connectionInfo).toString(); - } +public class ViewState implements Serializable { + + private String id; + + private String name; + + private boolean dirty = false; + + private ReportFile file; + + private boolean readOnly = false; + + private boolean editable = true; + + private boolean enableMdx = false; + + private Date lastActive = new Date(); + + private ConnectionInfo connectionInfo; + + private PivotModel model; + + private Serializable rendererState; + + private Serializable chartState; + + private Map parameters; + + private Map layoutRegions; + + /** + * @param id + * @param name + */ + public ViewState(String id, String name) { + if (id == null) { + throw new NullArgumentException("id"); + } + + if (name == null) { + throw new NullArgumentException("name"); + } + + this.id = id; + this.name = name; + this.layoutRegions = new HashMap(); + } + + /** + * @param id + * @param name + * @param connectionInfo + * @param model + * @param file + */ + public ViewState(String id, String name, ConnectionInfo connectionInfo, + PivotModel model, ReportFile file) { + if (id == null) { + throw new NullArgumentException("id"); + } + + if (name == null) { + throw new NullArgumentException("name"); + } + + this.id = id; + this.name = name; + this.connectionInfo = connectionInfo; + this.model = model; + this.file = file; + this.layoutRegions = new HashMap(); + } + + /** + * @return the id + */ + public String getId() { + return id; + } + + /** + * @return the name + */ + public String getName() { + return name; + } + + /** + * @param name the name to set + */ + public void setName(String name) { + if (name == null) { + throw new NullArgumentException("name"); + } + + this.name = name; + } + + public boolean isEnableMdx() { + return enableMdx; + } + + public void setEnableMdx(boolean enableMdx) { + this.enableMdx = enableMdx; + } + + /** + * @return the file + */ + public ReportFile getFile() { + return file; + } + + /** + * @param file the file to set + */ + public void setFile(ReportFile file) { + this.file = file; + } + + /** + * @return the lastActive + */ + public Date getLastActive() { + return lastActive; + } + + /** + * @return the connectionInfo + */ + public ConnectionInfo getConnectionInfo() { + return connectionInfo; + } + + /** + * @param connectionInfo the connectionInfo to set + */ + public void setConnectionInfo(ConnectionInfo connectionInfo) { + this.connectionInfo = connectionInfo; + } + + /** + * @return the readOnly + */ + public boolean isReadOnly() { + return readOnly; + } + + /** + * @param readOnly the readOnly to set + */ + public void setReadOnly(boolean readOnly) { + this.readOnly = readOnly; + } + + /** + * @return the editable + */ + public boolean isEditable() { + return editable; + } + + /** + * @param editable the editable to set + */ + public void setEditable(boolean editable) { + this.editable = editable; + } + + /** + * @return the model + */ + public PivotModel getModel() { + return model; + } + + /** + * @param model the model to set + */ + public void setModel(PivotModel model) { + this.model = model; + } + + /** + * @return the rendererState + */ + public Serializable getRendererState() { + return rendererState; + } + + /** + * @param rendererState the rendererState to set + */ + public void setRendererState(Serializable rendererState) { + this.rendererState = rendererState; + } + + /** + * @return the chartState + */ + public Serializable getChartState() { + return chartState; + } + + /** + * @param chartState the chartState to set + */ + public void setChartState(Serializable chartState) { + this.chartState = chartState; + } + + /** + * @return the parameters + */ + public Map getParameters() { + return parameters; + } + + /** + * @param parameters the parameters to set + */ + public void setParameters(Map parameters) { + this.parameters = parameters; + } + + /** + * @return the layoutRegions + */ + public Map getLayoutRegions() { + return layoutRegions; + } + + /** + * @param region + * @return + */ + public boolean isRegionVisible(LayoutRegion region) { + if (region == null) { + throw new NullArgumentException("region"); + } + + return !Boolean.FALSE.equals(layoutRegions.get(region)); + } + + /** + * @param region + * @param visible + */ + public void setRegionVisible(LayoutRegion region, boolean visible) { + if (region == null) { + throw new NullArgumentException("region"); + } + + layoutRegions.put(region, visible); + } + + /** + * @return the dirty + */ + public boolean isDirty() { + return dirty; + } + + /** + * @param dirty the dirty to set + */ + public void setDirty(boolean dirty) { + this.dirty = dirty; + } + + public void update() { + this.lastActive = new Date(); + } + + /** + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return new ToStringBuilder(this).append("id", id).append("name", name) + .append("connectionInfo", connectionInfo).toString(); + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/state/ViewStateEvent.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/state/ViewStateEvent.java index 7e8ace03..61460b2b 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/state/ViewStateEvent.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/state/ViewStateEvent.java @@ -4,32 +4,31 @@ public class ViewStateEvent extends EventObject { - private static final long serialVersionUID = -8755698962396196967L; - - private ViewState state; - - /** - * @param source - * @param state - */ - public ViewStateEvent(Object source, ViewState state) { - super(source); - - this.state = state; - } - - /** - * @return the state - */ - public ViewState getState() { - return state; - } - - /** - * @param state - * the state to set - */ - public void setState(ViewState state) { - this.state = state; - } + private static final long serialVersionUID = -8755698962396196967L; + + private ViewState state; + + /** + * @param source + * @param state + */ + public ViewStateEvent(Object source, ViewState state) { + super(source); + + this.state = state; + } + + /** + * @return the state + */ + public ViewState getState() { + return state; + } + + /** + * @param state the state to set + */ + public void setState(ViewState state) { + this.state = state; + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/state/ViewStateHolder.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/state/ViewStateHolder.java index e367020b..74ae344c 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/state/ViewStateHolder.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/state/ViewStateHolder.java @@ -39,403 +39,417 @@ @SessionScoped public class ViewStateHolder implements Serializable { - private static final long serialVersionUID = -7947800606762703855L; + private static final long serialVersionUID = -7947800606762703855L; - private static final long MINUTE = 60; + private static final long MINUTE = 60; - private Logger log = LoggerFactory.getLogger(getClass()); + private Logger log = LoggerFactory.getLogger(getClass()); - @ManagedProperty(value = "#{settings}") - private Settings settings; + @ManagedProperty(value = "#{settings}") + private Settings settings; - @ManagedProperty(value = "#{dataSourceManager}") - private DataSourceManager dataSourceManager; + @ManagedProperty(value = "#{dataSourceManager}") + private DataSourceManager dataSourceManager; - private Map states = new LinkedHashMap(); + private Map states = new LinkedHashMap(); - private List viewStateListeners = new ArrayList(); + private List viewStateListeners = new ArrayList(); - private Timer timer; + private transient Timer timer; - private long checkInterval = 1 * MINUTE; + private long checkInterval = 1 * MINUTE; - private long keepAliveInterval = 1 * MINUTE; + private long keepAliveInterval = 1 * MINUTE; - private long expires = 5 * MINUTE; + private long expires = 5 * MINUTE; - private String sessionId; + private String sessionId; - @PostConstruct - protected void initialize() { - ExternalContext context = FacesContext.getCurrentInstance() - .getExternalContext(); - HttpSession session = (HttpSession) context.getSession(true); - this.sessionId = session.getId(); + @PostConstruct + protected void initialize() { + ExternalContext context = FacesContext.getCurrentInstance() + .getExternalContext(); + HttpSession session = (HttpSession) context.getSession(true); + this.sessionId = session.getId(); - if (log.isInfoEnabled()) { - log.info("Initializing view state holder for session : " - + sessionId); - log.info(String.format("Check interval : %d secs.", checkInterval)); - log.info(String.format("Keep alive interval : %d secs.", - keepAliveInterval)); - log.info(String.format("Expires : %d secs.", expires)); - } + if (log.isInfoEnabled()) { + log.info("Initializing view state holder for session : " + + sessionId); + log.info(String.format("Check interval : %d secs.", checkInterval)); + log.info(String.format("Keep alive interval : %d secs.", + keepAliveInterval)); + log.info(String.format("Expires : %d secs.", expires)); + } - // As there's a no reliable way to clean up resources on a view scoped - // managed bean while the session is alive, we need to periodically - // check for stale connections and close them. - this.timer = new Timer(); + // As there's a no reliable way to clean up resources on a view scoped + // managed bean while the session is alive, we need to periodically + // check for stale connections and close them. + this.timer = new Timer(); - timer.scheduleAtFixedRate(new TimerTask() { + timer.scheduleAtFixedRate(new TimerTask() { - @Override - public void run() { - checkAbandonedModels(); - } - }, MINUTE * 1000, checkInterval * 1000); - } + @Override + public void run() { + checkAbandonedModels(); + } + }, MINUTE * 1000, checkInterval * 1000); + } - @PreDestroy - protected void destroy() { - if (log.isInfoEnabled()) { - log.info("Destroying view state holder for session : {}", sessionId); - } + @PreDestroy + protected void destroy() { + if (log.isInfoEnabled()) { + log.info("Destroying view state holder for session : {}", sessionId); + } - this.timer.cancel(); - this.timer.purge(); + this.timer.cancel(); + this.timer.purge(); - this.viewStateListeners.clear(); + this.viewStateListeners.clear(); - clearStates(); - } + clearStates(); + } - protected synchronized void checkAbandonedModels() { - if (log.isDebugEnabled()) { - log.debug("Checking for abandoned view states for session : " - + sessionId); - log.debug("Current view state count for session : {}", - states.size()); - } + protected synchronized void checkAbandonedModels() { + if (log.isDebugEnabled()) { + log.debug("Checking for abandoned view states for session : " + + sessionId); + log.debug("Current view state count for session : {}", + states.size()); + } - Set keys = new HashSet(states.keySet()); - - Date now = new Date(); - - for (String key : keys) { - ViewState state = states.get(key); + Set keys = new HashSet(states.keySet()); + + Date now = new Date(); + + for (String key : keys) { + ViewState state = states.get(key); - long elapsed = now.getTime() - state.getLastActive().getTime(); + long elapsed = now.getTime() - state.getLastActive().getTime(); - if (expires * 1000 <= elapsed) { - if (log.isInfoEnabled()) { - log.info("Found an abandoned view sate : {}", state); - } - - unregisterState(state); - } - } - } - - /** - * @param id - */ - public synchronized void keepAlive(String id) { - ViewState state = getState(id); - - if (log.isDebugEnabled()) { - log.debug("Received a keep alive request : {}", state); - } - - if (state != null) { - state.update(); - } - } - - /** - * @param id - * @return - */ - public ViewState getState(String id) { - return states.get(id); - } - - public synchronized List getStates() { - List list = new ArrayList(states.size()); - - for (String id : states.keySet()) { - list.add(states.get(id)); - } - - return list; - } - - /** - * @param state - */ - public synchronized void registerState(ViewState state) { - if (state == null) { - throw new IllegalArgumentException( - "Required argument 'state' is null."); - } - - ViewState oldState = states.get(state.getId()); - if (oldState != null) { - if (oldState == state) { - return; - } - - unregisterState(oldState); - } - - states.put(state.getId(), state); - - fireViewRegistered(state); - - if (log.isInfoEnabled()) { - log.info("View state is registered : {}", state); - log.info("Current view state count for session : {}", states.size()); - } - } - - /** - * @param id - */ - public synchronized void unregisterState(String id) { - if (id == null) { - throw new IllegalArgumentException( - "Required argument 'id' is null."); - } - - ViewState state = states.get(id); - - if (state != null) { - unregisterState(state); - } - } - - /** - * @param state - */ - protected synchronized void unregisterState(ViewState state) { - PivotModel model = state.getModel(); - if (model != null && model.isInitialized()) { - model.destroy(); - } - - states.remove(state.getId()); - - fireViewUnregistered(state); - - if (log.isInfoEnabled()) { - log.info("View state is unregistered : {}", state); - log.info("Current view state count for session : {}", states.size()); - } - } - - protected synchronized void clearStates() { - for (ViewState state : states.values()) { - unregisterState(state); - } - } - - /** - * Create an empty view state. - * - * @return - */ - public ViewState createNewState() { - List catalogs = dataSourceManager.getCatalogs(); - - ConnectionInfo connectionInfo = null; - - if (catalogs.size() == 1) { - connectionInfo = new ConnectionInfo(catalogs.get(0).getName(), null); - } - - return createNewState(connectionInfo, null); - } - - /** - * @param connectionInfo - * @param viewId - * @return - */ - public ViewState createNewState(ConnectionInfo connectionInfo, String viewId) { - String id; - - if (viewId == null) { - id = UUID.randomUUID().toString(); - } else { - id = viewId; - } - - FacesContext context = FacesContext.getCurrentInstance(); - - ResourceBundle messages = context.getApplication().getResourceBundle( - context, "msg"); - MessageFormat mf = new MessageFormat( - messages.getString("label.untitled")); - - List stateList = getStates(); - - Set names = new HashSet(stateList.size()); - - for (ViewState state : stateList) { - names.add(state.getName()); - } - - int count = 1; - - String name = null; - while (name == null) { - name = mf.format(new Object[] { count }); - - if (names.contains(name)) { - name = null; - count++; - } - } - - PivotModel model = null; - - if (connectionInfo != null) { - OlapDataSource dataSource = dataSourceManager - .getDataSource(connectionInfo); - - model = new PivotModelImpl(dataSource); - - HierarchicalConfiguration configuration = settings - .getConfiguration(); - - try { - model.restoreSettings(configuration.configurationAt("model")); - } catch (IllegalArgumentException e) { - } - } - - return new ViewState(id, name, connectionInfo, model, null); - } - - /** - * @param state - */ - protected void fireViewRegistered(ViewState state) { - ViewStateEvent e = new ViewStateEvent(this, state); - - List copiedListeners = new ArrayList( - viewStateListeners); - for (ViewStateListener listener : copiedListeners) { - listener.viewRegistered(e); - } - } - - /** - * @param state - */ - protected void fireViewUnregistered(ViewState state) { - ViewStateEvent e = new ViewStateEvent(this, state); - - List copiedListeners = new ArrayList( - viewStateListeners); - for (ViewStateListener listener : copiedListeners) { - listener.viewUnregistered(e); - } - } - - /** - * @param listener - */ - public void addViewStateListener(ViewStateListener listener) { - if (listener == null) { - throw new NullArgumentException("listener"); - } - - viewStateListeners.add(listener); - } - - /** - * @param listener - */ - public void removeViewStateListener(ViewStateListener listener) { - if (listener == null) { - throw new NullArgumentException("listener"); - } - - viewStateListeners.remove(listener); - } - - /** - * @return the settings - */ - public Settings getSettings() { - return settings; - } - - /** - * @param settings - * the settings to set - */ - public void setSettings(Settings settings) { - this.settings = settings; - } - - /** - * @return the dataSourceManager - */ - public DataSourceManager getDataSourceManager() { - return dataSourceManager; - } - - /** - * @param dataSourceManager - * the dataSourceManager to set - */ - public void setDataSourceManager(DataSourceManager dataSourceManager) { - this.dataSourceManager = dataSourceManager; - } - - /** - * @return the checkInterval - */ - public long getCheckInterval() { - return checkInterval; - } - - /** - * @param checkInterval - * the checkInterval to set - */ - public void setCheckInterval(long checkInterval) { - this.checkInterval = checkInterval; - } - - /** - * @return the keepAliveInterval - */ - public long getKeepAliveInterval() { - return keepAliveInterval; - } - - /** - * @param keepAliveInterval - * the keepAliveInterval to set - */ - public void setKeepAliveInterval(long keepAliveInterval) { - this.keepAliveInterval = keepAliveInterval; - } - - /** - * @return the expires - */ - public long getExpires() { - return expires; - } - - /** - * @param expires - * the expires to set - */ - public void setExpires(long expires) { - this.expires = expires; - } -} \ No newline at end of file + if (expires * 1000 <= elapsed) { + if (log.isInfoEnabled()) { + log.info("Found an abandoned view sate : {}", state); + } + + unregisterState(state); + } + } + } + + /** + * @param id + */ + public synchronized void keepAlive(String id) { + ViewState state = getState(id); + + if (log.isDebugEnabled()) { + log.debug("Received a keep alive request : {}", state); + } + + if (state != null) { + state.update(); + } + } + + /** + * @param id + * @return + */ + public ViewState getState(String id) { + return states.get(id); + } + + public synchronized List getStates() { + List list = new ArrayList(states.size()); + + for (String id : states.keySet()) { + list.add(states.get(id)); + } + + return list; + } + + /** + * @param state + */ + public synchronized void registerState(ViewState state) { + if (state == null) { + throw new IllegalArgumentException( + "Required argument 'state' is null."); + } + + ViewState oldState = states.get(state.getId()); + if (oldState != null) { + if (oldState == state) { + return; + } + + unregisterState(oldState); + } + + states.put(state.getId(), state); + + fireViewRegistered(state); + + if (log.isInfoEnabled()) { + log.info("View state is registered : {}", state); + log.info("Current view state count for session : {}", states.size()); + } + } + + /** + * @param id + */ + public synchronized void unregisterState(String id) { + if (id == null) { + throw new IllegalArgumentException( + "Required argument 'id' is null."); + } + + ViewState state = states.get(id); + + if (state != null) { + unregisterState(state); + } + } + + /** + * @param state + */ + protected synchronized void unregisterState(ViewState state) { + PivotModel model = state.getModel(); + if (model != null && model.isInitialized()) { + model.destroy(); + } + + states.remove(state.getId()); + + fireViewUnregistered(state); + + if (log.isInfoEnabled()) { + log.info("View state is unregistered : {}", state); + log.info("Current view state count for session : {}", states.size()); + } + } + + protected synchronized void clearStates() { + for (ViewState state : states.values()) { + unregisterState(state); + } + } + + /** + * Create an empty view state. + * + * @return + */ + public ViewState createNewState() { + List catalogs = dataSourceManager.getCatalogs(); + + ConnectionInfo connectionInfo = null; + + if (catalogs.size() == 1) { + connectionInfo = new ConnectionInfo(catalogs.get(0).getName(), null); + } + + return createNewState(connectionInfo, null); + } + + /** + * @param connectionInfo + * @param viewId + * @return + */ + public ViewState createNewState(ConnectionInfo connectionInfo, String viewId) { + String id; + + if (viewId == null) { + id = UUID.randomUUID().toString(); + } else { + id = viewId; + } + + FacesContext context = FacesContext.getCurrentInstance(); + + ResourceBundle messages = context.getApplication().getResourceBundle( + context, "msg"); + MessageFormat mf = new MessageFormat( + messages.getString("label.untitled")); + + List stateList = getStates(); + + Set names = new HashSet(stateList.size()); + + for (ViewState state : stateList) { + names.add(state.getName()); + } + + int count = 1; + + String name = null; + while (name == null) { + name = mf.format(new Object[]{count}); + + if (names.contains(name)) { + name = null; + count++; + } + } + + PivotModel model = null; + + if (connectionInfo != null) { + OlapDataSource dataSource = dataSourceManager + .getDataSource(connectionInfo); + + model = new PivotModelImpl(dataSource); + + HierarchicalConfiguration configuration = settings + .getConfiguration(); + + try { + model.restoreSettings(configuration.configurationAt("model")); + } catch (IllegalArgumentException e) { + } + } + + return new ViewState(id, name, connectionInfo, model, null); + } + + /** + * @param state + */ + protected void fireViewRegistered(ViewState state) { + ViewStateEvent e = new ViewStateEvent(this, state); + + List copiedListeners = new ArrayList( + viewStateListeners); + for (ViewStateListener listener : copiedListeners) { + listener.viewRegistered(e); + } + } + + /** + * @param state + */ + protected void fireViewUnregistered(ViewState state) { + ViewStateEvent e = new ViewStateEvent(this, state); + + List copiedListeners = new ArrayList( + viewStateListeners); + for (ViewStateListener listener : copiedListeners) { + listener.viewUnregistered(e); + } + } + + /** + * @param listener + */ + public void addViewStateListener(ViewStateListener listener) { + if (listener == null) { + throw new NullArgumentException("listener"); + } + + viewStateListeners.add(listener); + } + + /** + * @param listener + */ + public void removeViewStateListener(ViewStateListener listener) { + if (listener == null) { + throw new NullArgumentException("listener"); + } + + viewStateListeners.remove(listener); + } + + // TODO: get session attribut from settings + // TODO: use this function to manage visibility of the button + public boolean isLoggedIn() { + ExternalContext context = FacesContext.getCurrentInstance().getExternalContext(); + HttpSession session = (HttpSession) context.getSession(true); + + String authorizedUsername = (String) session.getAttribute("authorizedUsername"); + if(authorizedUsername == null) return false; + else if(authorizedUsername.isEmpty()) return false; + else return true; + } + + // TODO: get session attribut from settings + public void logOff() { + ExternalContext context = FacesContext.getCurrentInstance().getExternalContext(); + HttpSession session = (HttpSession) context.getSession(true); + session.setAttribute("authorizedUsername", null); + } + + /** + * @return the settings + */ + public Settings getSettings() { + return settings; + } + + /** + * @param settings the settings to set + */ + public void setSettings(Settings settings) { + this.settings = settings; + } + + /** + * @return the dataSourceManager + */ + public DataSourceManager getDataSourceManager() { + return dataSourceManager; + } + + /** + * @param dataSourceManager the dataSourceManager to set + */ + public void setDataSourceManager(DataSourceManager dataSourceManager) { + this.dataSourceManager = dataSourceManager; + } + + /** + * @return the checkInterval + */ + public long getCheckInterval() { + return checkInterval; + } + + /** + * @param checkInterval the checkInterval to set + */ + public void setCheckInterval(long checkInterval) { + this.checkInterval = checkInterval; + } + + /** + * @return the keepAliveInterval + */ + public long getKeepAliveInterval() { + return keepAliveInterval; + } + + /** + * @param keepAliveInterval the keepAliveInterval to set + */ + public void setKeepAliveInterval(long keepAliveInterval) { + this.keepAliveInterval = keepAliveInterval; + } + + /** + * @return the expires + */ + public long getExpires() { + return expires; + } + + /** + * @param expires the expires to set + */ + public void setExpires(long expires) { + this.expires = expires; + } +} diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/state/ViewStateListener.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/state/ViewStateListener.java index 2a4bed3c..fdd75fa4 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/state/ViewStateListener.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/state/ViewStateListener.java @@ -4,7 +4,7 @@ public interface ViewStateListener extends EventListener { - void viewRegistered(ViewStateEvent e); + void viewRegistered(ViewStateEvent e); - void viewUnregistered(ViewStateEvent e); + void viewUnregistered(ViewStateEvent e); } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/AggregationHandler.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/AggregationHandler.java index 91397ba9..ed169ef1 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/AggregationHandler.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/AggregationHandler.java @@ -20,228 +20,221 @@ @RequestScoped public class AggregationHandler { - @ManagedProperty(value = "#{viewHandler}") - private ViewHandler viewHandler; - - private DualListModel columnAggregators; - - private DualListModel columnHierarchyAggregators; - - private DualListModel columnMemberAggregators; - - private DualListModel rowAggregators; - - private DualListModel rowHierarchyAggregators; - - private DualListModel rowMemberAggregators; - - private ResourceBundle bundle; - - @PostConstruct - protected void initialize() { - FacesContext context = FacesContext.getCurrentInstance(); - - this.bundle = context.getApplication() - .getResourceBundle(context, "msg"); - - this.columnAggregators = createSelectionModel(Axis.COLUMNS, - AggregatorPosition.Grand); - this.columnHierarchyAggregators = createSelectionModel(Axis.COLUMNS, - AggregatorPosition.Hierarchy); - this.columnMemberAggregators = createSelectionModel(Axis.COLUMNS, - AggregatorPosition.Member); - - this.rowAggregators = createSelectionModel(Axis.ROWS, - AggregatorPosition.Grand); - this.rowHierarchyAggregators = createSelectionModel(Axis.ROWS, - AggregatorPosition.Hierarchy); - this.rowMemberAggregators = createSelectionModel(Axis.ROWS, - AggregatorPosition.Member); - } - - /** - * @return bundle - */ - protected ResourceBundle getBundle() { - return bundle; - } - - /** - * @param axis - * @param position - * @return - */ - protected DualListModel createSelectionModel(Axis axis, - AggregatorPosition position) { - TableRenderer renderer = viewHandler.getRenderer(); - - List selected = renderer.getAggregators(axis, position); - List available = renderer.getAggregatorFactory() - .getAvailableAggregations(); - - List unselectedItems = new ArrayList( - available.size()); - List selectedItems = new ArrayList( - available.size()); - - for (String name : available) { - String key = "label.aggregation.type." + name; - String label = bundle.getString(key); - - SelectItem item = new SelectItem(name, label); - - if (selected.contains(name)) { - selectedItems.add(item); - } else { - unselectedItems.add(item); - } - } - - return new DualListModel(unselectedItems, selectedItems); - } - - /** - * @param selection - * @param axis - * @param position - */ - protected void applySelection(DualListModel selection, - Axis axis, AggregatorPosition position) { - List items = selection.getTarget(); - - List aggregators = new ArrayList(items.size()); - - for (SelectItem item : items) { - aggregators.add((String) item.getValue()); - } - - TableRenderer renderer = viewHandler.getRenderer(); - renderer.setAggregators(axis, position, aggregators); - } - - public void apply() { - applySelection(rowAggregators, Axis.ROWS, AggregatorPosition.Grand); - applySelection(rowHierarchyAggregators, Axis.ROWS, - AggregatorPosition.Hierarchy); - applySelection(rowMemberAggregators, Axis.ROWS, - AggregatorPosition.Member); - - applySelection(columnAggregators, Axis.COLUMNS, - AggregatorPosition.Grand); - applySelection(columnHierarchyAggregators, Axis.COLUMNS, - AggregatorPosition.Hierarchy); - applySelection(columnMemberAggregators, Axis.COLUMNS, - AggregatorPosition.Member); - - viewHandler.render(); - } - - /** - * @return the viewHandler - */ - public ViewHandler getViewHandler() { - return viewHandler; - } - - /** - * @param viewHandler - * the viewHandler to set - */ - public void setViewHandler(ViewHandler viewHandler) { - this.viewHandler = viewHandler; - } - - /** - * @return the columnAggregators - */ - public DualListModel getColumnAggregators() { - return columnAggregators; - } - - /** - * @param columnAggregators - * the columnAggregators to set - */ - public void setColumnAggregators(DualListModel columnAggregators) { - this.columnAggregators = columnAggregators; - } - - /** - * @return the columnHierarchyAggregators - */ - public DualListModel getColumnHierarchyAggregators() { - return columnHierarchyAggregators; - } - - /** - * @param columnHierarchyAggregators - * the columnHierarchyAggregators to set - */ - public void setColumnHierarchyAggregators( - DualListModel columnHierarchyAggregators) { - this.columnHierarchyAggregators = columnHierarchyAggregators; - } - - /** - * @return the columnMemberAggregators - */ - public DualListModel getColumnMemberAggregators() { - return columnMemberAggregators; - } - - /** - * @param columnMemberAggregators - * the columnMemberAggregators to set - */ - public void setColumnMemberAggregators( - DualListModel columnMemberAggregators) { - this.columnMemberAggregators = columnMemberAggregators; - } - - /** - * @return the rowAggregators - */ - public DualListModel getRowAggregators() { - return rowAggregators; - } - - /** - * @param rowAggregators - * the rowAggregators to set - */ - public void setRowAggregators(DualListModel rowAggregators) { - this.rowAggregators = rowAggregators; - } - - /** - * @return the rowHierarchyAggregators - */ - public DualListModel getRowHierarchyAggregators() { - return rowHierarchyAggregators; - } - - /** - * @param rowHierarchyAggregators - * the rowHierarchyAggregators to set - */ - public void setRowHierarchyAggregators( - DualListModel rowHierarchyAggregators) { - this.rowHierarchyAggregators = rowHierarchyAggregators; - } - - /** - * @return the rowMemberAggregators - */ - public DualListModel getRowMemberAggregators() { - return rowMemberAggregators; - } - - /** - * @param rowMemberAggregators - * the rowMemberAggregators to set - */ - public void setRowMemberAggregators( - DualListModel rowMemberAggregators) { - this.rowMemberAggregators = rowMemberAggregators; - } + @ManagedProperty(value = "#{viewHandler}") + private ViewHandler viewHandler; + + private DualListModel columnAggregators; + + private DualListModel columnHierarchyAggregators; + + private DualListModel columnMemberAggregators; + + private DualListModel rowAggregators; + + private DualListModel rowHierarchyAggregators; + + private DualListModel rowMemberAggregators; + + private ResourceBundle bundle; + + @PostConstruct + protected void initialize() { + FacesContext context = FacesContext.getCurrentInstance(); + + this.bundle = context.getApplication() + .getResourceBundle(context, "msg"); + + this.columnAggregators = createSelectionModel(Axis.COLUMNS, + AggregatorPosition.Grand); + this.columnHierarchyAggregators = createSelectionModel(Axis.COLUMNS, + AggregatorPosition.Hierarchy); + this.columnMemberAggregators = createSelectionModel(Axis.COLUMNS, + AggregatorPosition.Member); + + this.rowAggregators = createSelectionModel(Axis.ROWS, + AggregatorPosition.Grand); + this.rowHierarchyAggregators = createSelectionModel(Axis.ROWS, + AggregatorPosition.Hierarchy); + this.rowMemberAggregators = createSelectionModel(Axis.ROWS, + AggregatorPosition.Member); + } + + /** + * @return bundle + */ + protected ResourceBundle getBundle() { + return bundle; + } + + /** + * @param axis + * @param position + * @return + */ + protected DualListModel createSelectionModel(Axis axis, + AggregatorPosition position) { + TableRenderer renderer = viewHandler.getRenderer(); + + List selected = renderer.getAggregators(axis, position); + List available = renderer.getAggregatorFactory() + .getAvailableAggregations(); + + List unselectedItems = new ArrayList( + available.size()); + List selectedItems = new ArrayList( + available.size()); + + for (String name : available) { + String key = "label.aggregation.type." + name; + String label = bundle.getString(key); + + SelectItem item = new SelectItem(name, label); + + if (selected.contains(name)) { + selectedItems.add(item); + } else { + unselectedItems.add(item); + } + } + + return new DualListModel(unselectedItems, selectedItems); + } + + /** + * @param selection + * @param axis + * @param position + */ + protected void applySelection(DualListModel selection, + Axis axis, AggregatorPosition position) { + List items = selection.getTarget(); + + List aggregators = new ArrayList(items.size()); + + for (SelectItem item : items) { + aggregators.add((String) item.getValue()); + } + + TableRenderer renderer = viewHandler.getRenderer(); + renderer.setAggregators(axis, position, aggregators); + } + + public void apply() { + applySelection(rowAggregators, Axis.ROWS, AggregatorPosition.Grand); + applySelection(rowHierarchyAggregators, Axis.ROWS, + AggregatorPosition.Hierarchy); + applySelection(rowMemberAggregators, Axis.ROWS, + AggregatorPosition.Member); + + applySelection(columnAggregators, Axis.COLUMNS, + AggregatorPosition.Grand); + applySelection(columnHierarchyAggregators, Axis.COLUMNS, + AggregatorPosition.Hierarchy); + applySelection(columnMemberAggregators, Axis.COLUMNS, + AggregatorPosition.Member); + + viewHandler.render(); + } + + /** + * @return the viewHandler + */ + public ViewHandler getViewHandler() { + return viewHandler; + } + + /** + * @param viewHandler the viewHandler to set + */ + public void setViewHandler(ViewHandler viewHandler) { + this.viewHandler = viewHandler; + } + + /** + * @return the columnAggregators + */ + public DualListModel getColumnAggregators() { + return columnAggregators; + } + + /** + * @param columnAggregators the columnAggregators to set + */ + public void setColumnAggregators(DualListModel columnAggregators) { + this.columnAggregators = columnAggregators; + } + + /** + * @return the columnHierarchyAggregators + */ + public DualListModel getColumnHierarchyAggregators() { + return columnHierarchyAggregators; + } + + /** + * @param columnHierarchyAggregators the columnHierarchyAggregators to set + */ + public void setColumnHierarchyAggregators( + DualListModel columnHierarchyAggregators) { + this.columnHierarchyAggregators = columnHierarchyAggregators; + } + + /** + * @return the columnMemberAggregators + */ + public DualListModel getColumnMemberAggregators() { + return columnMemberAggregators; + } + + /** + * @param columnMemberAggregators the columnMemberAggregators to set + */ + public void setColumnMemberAggregators( + DualListModel columnMemberAggregators) { + this.columnMemberAggregators = columnMemberAggregators; + } + + /** + * @return the rowAggregators + */ + public DualListModel getRowAggregators() { + return rowAggregators; + } + + /** + * @param rowAggregators the rowAggregators to set + */ + public void setRowAggregators(DualListModel rowAggregators) { + this.rowAggregators = rowAggregators; + } + + /** + * @return the rowHierarchyAggregators + */ + public DualListModel getRowHierarchyAggregators() { + return rowHierarchyAggregators; + } + + /** + * @param rowHierarchyAggregators the rowHierarchyAggregators to set + */ + public void setRowHierarchyAggregators( + DualListModel rowHierarchyAggregators) { + this.rowHierarchyAggregators = rowHierarchyAggregators; + } + + /** + * @return the rowMemberAggregators + */ + public DualListModel getRowMemberAggregators() { + return rowMemberAggregators; + } + + /** + * @param rowMemberAggregators the rowMemberAggregators to set + */ + public void setRowMemberAggregators( + DualListModel rowMemberAggregators) { + this.rowMemberAggregators = rowMemberAggregators; + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/AutocompletionSupport.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/AutocompletionSupport.java index 4a934cd1..5088f63d 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/AutocompletionSupport.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/AutocompletionSupport.java @@ -27,114 +27,113 @@ @RequestScoped public class AutocompletionSupport { - @ManagedProperty(value = "#{pivotStateManager.model}") - private PivotModel model; - - public static List FUNCTIONS = Arrays - .asList("Union", "Hierarchize"); - - public static List MEMBER_FUNCTIONS = Arrays.asList("Children"); - - public List complete(CompleteEvent event) throws OlapException { - List suggestions = new ArrayList(); - - if (model.isInitialized() && model.getCube() != null - && event.getToken() != null) { - Cube cube = model.getCube(); - - List context = getIdentifiers(event.getContext()); - - String token = decode(event.getToken()); - - if (context.isEmpty()) { - matchElements(token, suggestions, cube.getHierarchies()); - } else if (context.size() == 1) { - String name = context.get(0).getName(); - Hierarchy hierarchy = cube.getHierarchies().get(name); - - if (hierarchy != null) { - List members = hierarchy.getRootMembers(); - - matchElements(token, suggestions, members); - - for (Member member : members) { - if (member.isAll()) { - matchElements(token, suggestions, - member.getChildMembers()); - } - } - - matchKeywords(token, suggestions, MEMBER_FUNCTIONS); - } - } else { - Member parent = cube.lookupMember(context); - - if (parent != null) { - matchElements(token, suggestions, parent.getChildMembers()); - matchKeywords(token, suggestions, MEMBER_FUNCTIONS); - } - } - - if (context.isEmpty()) { - matchKeywords(token, suggestions, FUNCTIONS); - } - } - - return suggestions; - } - - private static void matchElements(String keyword, List result, - List elements) { - for (MetadataElement element : elements) { - if (keyword == null || element.getName().startsWith(keyword)) { - result.add("[" + element.getName() + "]"); - } - } - } - - private static void matchKeywords(String keyword, List result, - List elements) { - for (String element : elements) { - if (keyword == null || element.startsWith(keyword)) { - result.add(element); - } - } - } - - private static String decode(String token) { - if (StringUtils.isBlank(token) || "null".equals(token)) { - return null; - } - - try { - return URLDecoder.decode(token.trim(), "UTF-8"); - } catch (UnsupportedEncodingException e) { - throw new FacesException(e); - } - } - - private static List getIdentifiers(String token) { - String identifier = decode(token); - - if (identifier == null) { - return Collections.emptyList(); - } - - return IdentifierParser.parseIdentifier(identifier); - } - - /** - * @return the model - */ - public PivotModel getModel() { - return model; - } - - /** - * @param model - * the model to set - */ - public void setModel(PivotModel model) { - this.model = model; - } + @ManagedProperty(value = "#{pivotStateManager.model}") + private PivotModel model; + + public static List FUNCTIONS = Arrays + .asList("Union", "Hierarchize"); + + public static List MEMBER_FUNCTIONS = Arrays.asList("Children"); + + public List complete(CompleteEvent event) throws OlapException { + List suggestions = new ArrayList(); + + if (model.isInitialized() && model.getCube() != null + && event.getToken() != null) { + Cube cube = model.getCube(); + + List context = getIdentifiers(event.getContext()); + + String token = decode(event.getToken()); + + if (context.isEmpty()) { + matchElements(token, suggestions, cube.getHierarchies()); + } else if (context.size() == 1) { + String name = context.get(0).getName(); + Hierarchy hierarchy = cube.getHierarchies().get(name); + + if (hierarchy != null) { + List members = hierarchy.getRootMembers(); + + matchElements(token, suggestions, members); + + for (Member member : members) { + if (member.isAll()) { + matchElements(token, suggestions, + member.getChildMembers()); + } + } + + matchKeywords(token, suggestions, MEMBER_FUNCTIONS); + } + } else { + Member parent = cube.lookupMember(context); + + if (parent != null) { + matchElements(token, suggestions, parent.getChildMembers()); + matchKeywords(token, suggestions, MEMBER_FUNCTIONS); + } + } + + if (context.isEmpty()) { + matchKeywords(token, suggestions, FUNCTIONS); + } + } + + return suggestions; + } + + private static void matchElements(String keyword, List result, + List elements) { + for (MetadataElement element : elements) { + if (keyword == null || element.getName().startsWith(keyword)) { + result.add("[" + element.getName() + "]"); + } + } + } + + private static void matchKeywords(String keyword, List result, + List elements) { + for (String element : elements) { + if (keyword == null || element.startsWith(keyword)) { + result.add(element); + } + } + } + + private static String decode(String token) { + if (StringUtils.isBlank(token) || "null".equals(token)) { + return null; + } + + try { + return URLDecoder.decode(token.trim(), "UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new FacesException(e); + } + } + + private static List getIdentifiers(String token) { + String identifier = decode(token); + + if (identifier == null) { + return Collections.emptyList(); + } + + return IdentifierParser.parseIdentifier(identifier); + } + + /** + * @return the model + */ + public PivotModel getModel() { + return model; + } + + /** + * @param model the model to set + */ + public void setModel(PivotModel model) { + this.model = model; + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/CatalogChooser.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/CatalogChooser.java index f10b0212..5dbf486f 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/CatalogChooser.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/CatalogChooser.java @@ -29,278 +29,271 @@ @ViewScoped public class CatalogChooser implements Serializable { - private static final long serialVersionUID = 9032548845357820921L; + private static final long serialVersionUID = 9032548845357820921L; - @ManagedProperty(value = "#{settings}") - private Settings settings; + @ManagedProperty(value = "#{settings}") + private Settings settings; - @ManagedProperty(value = "#{dataSourceManager}") - private DataSourceManager dataSourceManager; + @ManagedProperty(value = "#{dataSourceManager}") + private DataSourceManager dataSourceManager; - @ManagedProperty(value = "#{viewStateHolder}") - private ViewStateHolder viewStateHolder; + @ManagedProperty(value = "#{viewStateHolder}") + private ViewStateHolder viewStateHolder; - private List catalogItems; + private List catalogItems; - private List cubeItems; + private List cubeItems; - private String catalogName; + private String catalogName; - private String cubeName; + private String cubeName; - private String viewId; + private String viewId; - private boolean editable; + private boolean editable; - public List getCatalogs() { - if (catalogItems == null) { - FacesContext context = FacesContext.getCurrentInstance(); - ResourceBundle messages = context.getApplication() - .getResourceBundle(context, "msg"); + public List getCatalogs() { + if (catalogItems == null) { + FacesContext context = FacesContext.getCurrentInstance(); + ResourceBundle messages = context.getApplication() + .getResourceBundle(context, "msg"); - try { - List catalogs = dataSourceManager.getCatalogs(); + try { + List catalogs = dataSourceManager.getCatalogs(); - this.catalogItems = new ArrayList(catalogs.size()); + this.catalogItems = new ArrayList(catalogs.size()); - UISelectItem defaultItem = new UISelectItem(); - defaultItem.setItemLabel(messages - .getString("message.catalog.chooser.default")); - defaultItem.setItemValue(""); + UISelectItem defaultItem = new UISelectItem(); + defaultItem.setItemLabel(messages + .getString("message.catalog.chooser.default")); + defaultItem.setItemValue(""); - catalogItems.add(defaultItem); + catalogItems.add(defaultItem); - for (CatalogInfo catalog : catalogs) { - UISelectItem item = new UISelectItem(); + for (CatalogInfo catalog : catalogs) { + UISelectItem item = new UISelectItem(); - item.setItemValue(catalog.getName()); - item.setItemLabel(catalog.getLabel()); - item.setItemDescription(catalog.getDescription()); + item.setItemValue(catalog.getName()); + item.setItemLabel(catalog.getLabel()); + item.setItemDescription(catalog.getDescription()); - catalogItems.add(item); - } - } catch (Exception e) { - String title = messages.getString("error.catalogList.title"); - String msg = e.getMessage(); + catalogItems.add(item); + } + } catch (Exception e) { + String title = messages.getString("error.catalogList.title"); + String msg = e.getMessage(); - context.addMessage(null, new FacesMessage( - FacesMessage.SEVERITY_ERROR, title, msg)); + context.addMessage(null, new FacesMessage( + FacesMessage.SEVERITY_ERROR, title, msg)); - Logger log = LoggerFactory.getLogger(getClass()); - if (log.isErrorEnabled()) { - log.error(msg, e); - } - } - } + Logger log = LoggerFactory.getLogger(getClass()); + if (log.isErrorEnabled()) { + log.error(msg, e); + } + } + } - return catalogItems; - } + return catalogItems; + } - public List getCubes() { - if (cubeItems == null) { - FacesContext context = FacesContext.getCurrentInstance(); - ResourceBundle messages = context.getApplication() - .getResourceBundle(context, "msg"); + public List getCubes() { + if (cubeItems == null) { + FacesContext context = FacesContext.getCurrentInstance(); + ResourceBundle messages = context.getApplication() + .getResourceBundle(context, "msg"); - this.cubeItems = new ArrayList(); + this.cubeItems = new ArrayList(); - UISelectItem defaultItem = new UISelectItem(); - defaultItem.setItemLabel(messages - .getString("message.cubeList.default")); - defaultItem.setItemValue(""); + UISelectItem defaultItem = new UISelectItem(); + defaultItem.setItemLabel(messages + .getString("message.cubeList.default")); + defaultItem.setItemValue(""); - cubeItems.add(defaultItem); + cubeItems.add(defaultItem); - if (catalogName != null) { - try { - List cubes = dataSourceManager - .getCubes(catalogName); + if (catalogName != null) { + try { + List cubes = dataSourceManager + .getCubes(catalogName); - for (CubeInfo cube : cubes) { - UISelectItem item = new UISelectItem(); + for (CubeInfo cube : cubes) { + UISelectItem item = new UISelectItem(); - item.setItemValue(cube.getName()); - item.setItemLabel(cube.getLabel()); - item.setItemDescription(cube.getDescription()); + item.setItemValue(cube.getName()); + item.setItemLabel(cube.getLabel()); + item.setItemDescription(cube.getDescription()); - cubeItems.add(item); - } - } catch (Exception e) { - ResourceBundle bundle = context.getApplication() - .getResourceBundle(context, "msg"); - - String title = bundle.getString("error.cubeList.title"); - String msg = e.getMessage(); - - context.addMessage(null, new FacesMessage( - FacesMessage.SEVERITY_ERROR, title, msg)); - - Logger log = LoggerFactory.getLogger(getClass()); - if (log.isErrorEnabled()) { - log.error(msg, e); - } - } - } - } - - return cubeItems; - } - - public void onCatalogChanged() { - this.cubeItems = null; - - if (getCubes().size() > 1) { - this.cubeName = (String) getCubes().get(1).getItemValue(); - } else { - this.cubeName = null; - } - } - - public boolean isNewReport() { - if (viewId == null) { - return true; - } - - ViewState state = viewStateHolder.getState(viewId); - - return state == null || state.getConnectionInfo() == null; - } - - public String proceed() { - FacesContext context = FacesContext.getCurrentInstance(); - Flash flash = context.getExternalContext().getFlash(); - - ConnectionInfo connectionInfo = new ConnectionInfo(catalogName, - cubeName); - - ViewState state = viewStateHolder.getState(viewId); - - if (state == null) { - state = viewStateHolder.createNewState(connectionInfo, viewId); - viewStateHolder.registerState(state); - } else { - OlapDataSource dataSource = dataSourceManager - .getDataSource(connectionInfo); - state.setModel(new PivotModelImpl(dataSource)); - state.setConnectionInfo(connectionInfo); - } - - flash.put("connectionInfo", connectionInfo); - flash.put("viewId", viewId); - - StringBuilder builder = new StringBuilder(); - builder.append("view"); - builder.append("?faces-redirect=true"); - builder.append("&"); - builder.append(settings.getViewParameterName()); - builder.append("="); - builder.append(viewId); - - return builder.toString(); - } - - /** - * @return the dataSourceManager - */ - public DataSourceManager getDataSourceManager() { - return dataSourceManager; - } - - /** - * @param dataSourceManager - * the dataSourceManager to set - */ - public void setDataSourceManager(DataSourceManager dataSourceManager) { - this.dataSourceManager = dataSourceManager; - } - - /** - * @return the settings - */ - public Settings getSettings() { - return settings; - } - - /** - * @param settings - * the settings to set - */ - public void setSettings(Settings settings) { - this.settings = settings; - } - - /** - * @return the viewStateHolder - */ - public ViewStateHolder getViewStateHolder() { - return viewStateHolder; - } - - /** - * @param viewStateHolder - * the viewStateHolder to set - */ - public void setViewStateHolder(ViewStateHolder viewStateHolder) { - this.viewStateHolder = viewStateHolder; - } - - /** - * @return the catalogName - */ - public String getCatalogName() { - return catalogName; - } - - /** - * @param catalogName - * the catalogName to set - */ - public void setCatalogName(String catalogName) { - this.catalogName = catalogName; - } - - /** - * @return the cubeName - */ - public String getCubeName() { - return cubeName; - } - - /** - * @param cubeName - * the cubeName to set - */ - public void setCubeName(String cubeName) { - this.cubeName = cubeName; - } - - /** - * @return the viewId - */ - public String getViewId() { - return viewId; - } - - /** - * @param viewId - * the viewId to set - */ - public void setViewId(String viewId) { - this.viewId = viewId; - } - - /** - * @return the editable - */ - public boolean isEditable() { - return editable; - } - - /** - * @param editable - * the editable to set - */ - public void setEditable(boolean editable) { - this.editable = editable; - } + cubeItems.add(item); + } + } catch (Exception e) { + ResourceBundle bundle = context.getApplication() + .getResourceBundle(context, "msg"); + + String title = bundle.getString("error.cubeList.title"); + String msg = e.getMessage(); + + context.addMessage(null, new FacesMessage( + FacesMessage.SEVERITY_ERROR, title, msg)); + + Logger log = LoggerFactory.getLogger(getClass()); + if (log.isErrorEnabled()) { + log.error(msg, e); + } + } + } + } + + return cubeItems; + } + + public void onCatalogChanged() { + this.cubeItems = null; + + if (getCubes().size() > 1) { + this.cubeName = (String) getCubes().get(1).getItemValue(); + } else { + this.cubeName = null; + } + } + + public boolean isNewReport() { + if (viewId == null) { + return true; + } + + ViewState state = viewStateHolder.getState(viewId); + + return state == null || state.getConnectionInfo() == null; + } + + public String proceed() { + FacesContext context = FacesContext.getCurrentInstance(); + Flash flash = context.getExternalContext().getFlash(); + + ConnectionInfo connectionInfo = new ConnectionInfo(catalogName, + cubeName); + + ViewState state = viewStateHolder.getState(viewId); + + if (state == null) { + state = viewStateHolder.createNewState(connectionInfo, viewId); + viewStateHolder.registerState(state); + } else { + OlapDataSource dataSource = dataSourceManager + .getDataSource(connectionInfo); + state.setModel(new PivotModelImpl(dataSource)); + state.setConnectionInfo(connectionInfo); + } + + flash.put("connectionInfo", connectionInfo); + flash.put("viewId", viewId); + + StringBuilder builder = new StringBuilder(); + builder.append("view"); + builder.append("?faces-redirect=true"); + builder.append("&"); + builder.append(settings.getViewParameterName()); + builder.append("="); + builder.append(viewId); + + return builder.toString(); + } + + /** + * @return the dataSourceManager + */ + public DataSourceManager getDataSourceManager() { + return dataSourceManager; + } + + /** + * @param dataSourceManager the dataSourceManager to set + */ + public void setDataSourceManager(DataSourceManager dataSourceManager) { + this.dataSourceManager = dataSourceManager; + } + + /** + * @return the settings + */ + public Settings getSettings() { + return settings; + } + + /** + * @param settings the settings to set + */ + public void setSettings(Settings settings) { + this.settings = settings; + } + + /** + * @return the viewStateHolder + */ + public ViewStateHolder getViewStateHolder() { + return viewStateHolder; + } + + /** + * @param viewStateHolder the viewStateHolder to set + */ + public void setViewStateHolder(ViewStateHolder viewStateHolder) { + this.viewStateHolder = viewStateHolder; + } + + /** + * @return the catalogName + */ + public String getCatalogName() { + return catalogName; + } + + /** + * @param catalogName the catalogName to set + */ + public void setCatalogName(String catalogName) { + this.catalogName = catalogName; + } + + /** + * @return the cubeName + */ + public String getCubeName() { + return cubeName; + } + + /** + * @param cubeName the cubeName to set + */ + public void setCubeName(String cubeName) { + this.cubeName = cubeName; + } + + /** + * @return the viewId + */ + public String getViewId() { + return viewId; + } + + /** + * @param viewId the viewId to set + */ + public void setViewId(String viewId) { + this.viewId = viewId; + } + + /** + * @return the editable + */ + public boolean isEditable() { + return editable; + } + + /** + * @param editable the editable to set + */ + public void setEditable(boolean editable) { + this.editable = editable; + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/DefaultTableRenderer.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/DefaultTableRenderer.java index 7bf6eecd..aa255694 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/DefaultTableRenderer.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/DefaultTableRenderer.java @@ -7,69 +7,71 @@ public class DefaultTableRenderer extends TableRenderer { - private boolean visible = true; - - /** - * @return the visible - */ - public boolean isVisible() { - return visible; - } - - /** - * @param visible - * the visible to set - */ - public void setVisible(boolean visible) { - this.visible = visible; - } - - /** - * @see org.pivot4j.ui.table.TableRenderer#saveState() - */ - @Override - public Serializable saveState() { - Serializable[] states = new Serializable[2]; - - int index = 0; - - states[index++] = super.saveState(); - states[index++] = visible; - - return states; - } - - /** - * @see org.pivot4j.ui.table.TableRenderer#restoreState(java.io.Serializable) - */ - @Override - public void restoreState(Serializable state) { - Serializable[] states = (Serializable[]) state; - - int index = 0; - - super.restoreState(states[index++]); - - this.visible = (Boolean) states[index++]; - } - - /** - * @see org.pivot4j.ui.table.TableRenderer#saveSettings(org.apache.commons.configuration.HierarchicalConfiguration) - */ - @Override - public void saveSettings(HierarchicalConfiguration configuration) { - super.saveSettings(configuration); - - configuration.addProperty("[@visible]", visible); - } - - /** - * @see org.pivot4j.ui.table.TableRenderer#restoreSettings(org.apache.commons.configuration.HierarchicalConfiguration) - */ - @Override - public void restoreSettings(HierarchicalConfiguration configuration) { - super.restoreSettings(configuration); - - this.visible = configuration.getBoolean("[@visible]", true); - } + private boolean visible = true; + + /** + * @return the visible + */ + public boolean isVisible() { + return visible; + } + + /** + * @param visible the visible to set + */ + public void setVisible(boolean visible) { + this.visible = visible; + } + + /** + * @see org.pivot4j.ui.table.TableRenderer#saveState() + */ + @Override + public Serializable saveState() { + Serializable[] states = new Serializable[2]; + + int index = 0; + + states[index++] = super.saveState(); + states[index++] = visible; + + return states; + } + + /** + * @see + * org.pivot4j.ui.table.TableRenderer#restoreState(java.io.Serializable) + */ + @Override + public void restoreState(Serializable state) { + Serializable[] states = (Serializable[]) state; + + int index = 0; + + super.restoreState(states[index++]); + + this.visible = (Boolean) states[index++]; + } + + /** + * @see + * org.pivot4j.ui.table.TableRenderer#saveSettings(org.apache.commons.configuration.HierarchicalConfiguration) + */ + @Override + public void saveSettings(HierarchicalConfiguration configuration) { + super.saveSettings(configuration); + + configuration.addProperty("[@visible]", visible); + } + + /** + * @see + * org.pivot4j.ui.table.TableRenderer#restoreSettings(org.apache.commons.configuration.HierarchicalConfiguration) + */ + @Override + public void restoreSettings(HierarchicalConfiguration configuration) { + super.restoreSettings(configuration); + + this.visible = configuration.getBoolean("[@visible]", true); + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/DrillThroughDataModel.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/DrillThroughDataModel.java index 743630c1..3e329414 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/DrillThroughDataModel.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/DrillThroughDataModel.java @@ -28,274 +28,281 @@ @ViewScoped public class DrillThroughDataModel extends LazyDataModel> { - private static final long serialVersionUID = 2554173601960871316L; + private static final long serialVersionUID = 2554173601960871316L; - private static final String ROW_KEY = "_id"; + private static final String ROW_KEY = "_id"; - public static final int DEFAULT_PAGE_SIZE = 15; + public static final int DEFAULT_PAGE_SIZE = 15; - @ManagedProperty(value = "#{pivotStateManager}") - private PivotStateManager stateManager; + @ManagedProperty(value = "#{pivotStateManager}") + private PivotStateManager stateManager; - private Cell cell; + private Cell cell; - private int maximumRows = 0; + private int maximumRows = 0; - private List selection = Collections.emptyList(); + private List selection = Collections.emptyList(); - private List columns = Collections.emptyList(); + private List columns = Collections.emptyList(); - public DrillThroughDataModel() { - setPageSize(DEFAULT_PAGE_SIZE); - } + public DrillThroughDataModel() { + setPageSize(DEFAULT_PAGE_SIZE); + } - public List getColumns() { - return columns; - } + public List getColumns() { + return columns; + } - /** - * @see org.primefaces.model.LazyDataModel#getRowKey(java.lang.Object) - */ - @Override - public Object getRowKey(Map row) { - return row.get(ROW_KEY); - } + /** + * @see org.primefaces.model.LazyDataModel#getRowKey(java.lang.Object) + */ + @Override + public Object getRowKey(Map row) { + return row.get(ROW_KEY); + } - /** - * @param cell - */ - public void initialize(Cell cell) { - initialize(cell, null, 0); - } - - /** - * @param cell - * @param selection - * @param maximumRows - */ - public void initialize(Cell cell, List selection, - int maximumRows) { - if (cell == null) { - throw new NullArgumentException("cell"); - } - - this.cell = cell; - - if (selection == null) { - this.selection = Collections.emptyList(); - } else { - this.selection = Collections.unmodifiableList(selection); - } - - this.maximumRows = maximumRows; - - ResultSet result = null; - Statement stmt = null; - - try { - result = execute(); - stmt = result.getStatement(); - - boolean scrollable = (result.getStatement().getResultSetType() == ResultSet.TYPE_SCROLL_SENSITIVE); - - int rowCount = 0; - - if (scrollable && result.last()) { - rowCount = result.getRow(); - - result.beforeFirst(); - } else { - while (result.next()) { - rowCount++; - - if (maximumRows > 0 && rowCount >= maximumRows) { - break; - } - } - } - - if (maximumRows > 0) { - rowCount = Math.min(rowCount, maximumRows); - } - - setRowCount(rowCount); - - ResultSetMetaData metadata = result.getMetaData(); - - int count = metadata.getColumnCount(); - - this.columns = new LinkedList(); - - for (int i = 1; i <= count; i++) { - columns.add(new DataColumn(metadata.getColumnLabel(i), metadata - .getColumnName(i))); - } - } catch (SQLException e) { - throw new FacesException(e); - } finally { - DbUtils.closeQuietly(result); - DbUtils.closeQuietly(stmt); - } - } - - public void reset() { - this.cell = null; - this.maximumRows = 0; - this.columns = Collections.emptyList(); - this.selection = Collections.emptyList(); - - setRowCount(0); - setRowIndex(-1); - } - - protected ResultSet execute() { - if (cell == null) { - throw new IllegalStateException( - "The model has not been initialized."); - } - - DrillThrough transform = stateManager.getModel().getTransform( - DrillThrough.class); - - if (selection.isEmpty()) { - return transform.drillThrough(cell); - } else { - return transform.drillThrough(cell, selection, maximumRows); - } - } - - /** - * @see org.primefaces.model.LazyDataModel#load(int, int, java.lang.String, - * org.primefaces.model.SortOrder, java.util.Map) - */ - public List> load(int first, int pageSize, - String sortField, SortOrder sortOrder, Map filters) { - if (columns.isEmpty()) { - return Collections.emptyList(); - } - - List> data = new ArrayList>( - pageSize); - - ResultSet result = null; - Statement stmt = null; - - try { - result = execute(); - stmt = result.getStatement(); - - boolean scrollable = (result.getStatement().getResultSetType() == ResultSet.TYPE_SCROLL_SENSITIVE); - - int rowIndex = 0; - - if (scrollable) { - rowIndex = first; - - result.absolute(rowIndex + 1); - } else { - while (rowIndex < first) { - if (!result.next()) { - return Collections.> emptyList(); - } - - rowIndex++; - } - } - - List columnList = getColumns(); - - for (int i = 0; i < pageSize; i++) { - if (result.next()) { - Map row = new HashMap( - columnList.size() + 1); - - for (DataColumn column : columnList) { - if (ROW_KEY.equals(column.getName())) { - row.put(ROW_KEY, rowIndex + i + 1); - } else { - row.put(column.getName(), - result.getObject(column.getName())); - } - } - - data.add(row); - } else { - break; - } - } - } catch (SQLException e) { - throw new FacesException(e); - } finally { - DbUtils.closeQuietly(result); - DbUtils.closeQuietly(stmt); - } - - return data; - } - - /** - * @return the maximumRows - */ - public int getMaximumRows() { - return maximumRows; - } - - /** - * @return the cell - */ - public Cell getCell() { - return cell; - } - - /** - * @return the selection - */ - public List getSelection() { - return selection; - } - - /** - * @return the stateManager - */ - public PivotStateManager getStateManager() { - return stateManager; - } - - /** - * @param stateManager - * the stateManager to set - */ - public void setStateManager(PivotStateManager stateManager) { - this.stateManager = stateManager; - } - - public static class DataColumn { - - private String label; - - private String name; - - /** - * @param label - * @param name - */ - DataColumn(String label, String name) { - this.label = label; - this.name = name; - } - - /** - * @return label - */ - public String getLabel() { - return label; - } - - /** - * @return name - */ - public String getName() { - return name; - } - } + /** + * @param cell + */ + public void initialize(Cell cell) { + initialize(cell, null, 0); + } + + /** + * @param cell + * @param selection + * @param maximumRows + */ + public void initialize(Cell cell, List selection, + int maximumRows) { + if (cell == null) { + throw new NullArgumentException("cell"); + } + + this.cell = cell; + + if (selection == null) { + this.selection = Collections.emptyList(); + } else { + this.selection = Collections.unmodifiableList(selection); + } + + this.maximumRows = maximumRows; + + ResultSet result = null; + Statement stmt = null; + + try { + result = execute(); + stmt = result.getStatement(); + + boolean scrollable = false; + try { + scrollable = (result.getStatement().getResultSetType() == ResultSet.TYPE_SCROLL_SENSITIVE); + } catch (Exception e) { + } + + int rowCount = 0; + + if (scrollable && result.last()) { + rowCount = result.getRow(); + + result.beforeFirst(); + } else { + while (result.next()) { + rowCount++; + + if (maximumRows > 0 && rowCount >= maximumRows) { + break; + } + } + } + + if (maximumRows > 0) { + rowCount = Math.min(rowCount, maximumRows); + } + + setRowCount(rowCount); + + ResultSetMetaData metadata = result.getMetaData(); + + int count = metadata.getColumnCount(); + + this.columns = new LinkedList(); + + for (int i = 1; i <= count; i++) { + columns.add(new DataColumn(metadata.getColumnLabel(i), metadata + .getColumnName(i))); + } + } catch (SQLException e) { + throw new FacesException(e); + } finally { + DbUtils.closeQuietly(result); + DbUtils.closeQuietly(stmt); + } + } + + public void reset() { + this.cell = null; + this.maximumRows = 0; + this.columns = Collections.emptyList(); + this.selection = Collections.emptyList(); + + setRowCount(0); + setRowIndex(-1); + } + + protected ResultSet execute() { + if (cell == null) { + throw new IllegalStateException( + "The model has not been initialized."); + } + + DrillThrough transform = stateManager.getModel().getTransform( + DrillThrough.class); + + if (selection.isEmpty()) { + return transform.drillThrough(cell); + } else { + return transform.drillThrough(cell, selection, maximumRows); + } + } + + /** + * @see org.primefaces.model.LazyDataModel#load(int, int, java.lang.String, + * org.primefaces.model.SortOrder, java.util.Map) + */ + public List> load(int first, int pageSize, + String sortField, SortOrder sortOrder, Map filters) { + if (columns.isEmpty()) { + return Collections.emptyList(); + } + + List> data = new ArrayList>( + pageSize); + + ResultSet result = null; + Statement stmt = null; + + try { + result = execute(); + stmt = result.getStatement(); + + boolean scrollable = false; + try { + scrollable = (result.getStatement().getResultSetType() == ResultSet.TYPE_SCROLL_SENSITIVE); + } catch (Exception e) { + } + + int rowIndex = 0; + + if (scrollable) { + rowIndex = first; + + result.absolute(rowIndex + 1); + } else { + while (rowIndex < first) { + if (!result.next()) { + return Collections.>emptyList(); + } + + rowIndex++; + } + } + + List columnList = getColumns(); + + for (int i = 0; i < pageSize; i++) { + if (result.next()) { + Map row = new HashMap( + columnList.size() + 1); + + for (DataColumn column : columnList) { + if (ROW_KEY.equals(column.getName())) { + row.put(ROW_KEY, rowIndex + i + 1); + } else { + row.put(column.getName(), + result.getObject(column.getName())); + } + } + + data.add(row); + } else { + break; + } + } + } catch (SQLException e) { + throw new FacesException(e); + } finally { + DbUtils.closeQuietly(result); + DbUtils.closeQuietly(stmt); + } + + return data; + } + + /** + * @return the maximumRows + */ + public int getMaximumRows() { + return maximumRows; + } + + /** + * @return the cell + */ + public Cell getCell() { + return cell; + } + + /** + * @return the selection + */ + public List getSelection() { + return selection; + } + + /** + * @return the stateManager + */ + public PivotStateManager getStateManager() { + return stateManager; + } + + /** + * @param stateManager the stateManager to set + */ + public void setStateManager(PivotStateManager stateManager) { + this.stateManager = stateManager; + } + + public static class DataColumn { + + private String label; + + private String name; + + /** + * @param label + * @param name + */ + DataColumn(String label, String name) { + this.label = label; + this.name = name; + } + + /** + * @return label + */ + public String getLabel() { + return label; + } + + /** + * @return name + */ + public String getName() { + return name; + } + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/DrillThroughHandler.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/DrillThroughHandler.java index d1f0cc93..a338c2bd 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/DrillThroughHandler.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/DrillThroughHandler.java @@ -1,5 +1,6 @@ package org.pivot4j.analytics.ui; +import java.io.Serializable; import java.util.Arrays; import java.util.LinkedList; import java.util.List; @@ -28,229 +29,228 @@ @ManagedBean(name = "drillThroughHandler") @ViewScoped -public class DrillThroughHandler implements NodeFilter { - - @ManagedProperty(value = "#{pivotStateManager}") - private PivotStateManager stateManager; - - @ManagedProperty(value = "#{drillThroughData}") - private DrillThroughDataModel data; - - private CubeNode cubeNode; - - private TreeNode[] selection; - - private int maximumRows = 0; - - private DataTable table; - - public void update() { - update(data.getCell()); - } - - /** - * @param cell - */ - public void update(Cell cell) { - if (cell == null) { - throw new NullArgumentException("cell"); - } - - List elements = new LinkedList(); - - if (selection != null) { - for (TreeNode node : selection) { - MetadataElement elem = ((MetadataNode) node).getObject(); - elements.add(elem); - } - } - - data.setRowIndex(-1); - data.initialize(cell, elements, maximumRows); - - table.setFirst(0); - } - - public void reset() { - data.reset(); - - this.cubeNode = null; - this.selection = null; - this.maximumRows = 0; - } - - /** - * @return the cubeNode - */ - public CubeNode getCubeNode() { - if (cubeNode != null) { - return cubeNode; - } - - PivotModel model = stateManager.getModel(); - - if (model != null && model.isInitialized() && data.getCell() != null) { - this.cubeNode = new CubeNode(model.getCube()); - cubeNode.setNodeFilter(this); - } - - return cubeNode; - } - - /** - * @param cubeNode - * the cubeNode to set - */ - public void setCubeNode(CubeNode cubeNode) { - this.cubeNode = cubeNode; - } - - /** - * @return the data - */ - public DrillThroughDataModel getData() { - return data; - } - - /** - * @param data - * the data to set - */ - public void setData(DrillThroughDataModel data) { - this.data = data; - } - - /** - * @return the selection - */ - public TreeNode[] getSelection() { - return selection; - } - - /** - * @param newSelection - * the newSelection to set - */ - public void setSelection(TreeNode[] newSelection) { - if (newSelection == null) { - this.selection = null; - } else { - this.selection = Arrays.copyOf(newSelection, newSelection.length); - } - } - - /** - * @return the maximumRows - */ - public int getMaximumRows() { - return maximumRows; - } - - /** - * @param maximumRows - * the maximumRows to set - */ - public void setMaximumRows(int maximumRows) { - this.maximumRows = maximumRows; - } - - /** - * @see org.pivot4j.analytics.component.tree.NodeFilter#isSelected(org.olap4j.metadata.MetadataElement) - */ - @Override - public boolean isSelected(T element) { - return data.getSelection().contains(element); - } - - /** - * @see org.pivot4j.analytics.component.tree.NodeFilter#isSelectable(org.olap4j.metadata.MetadataElement) - */ - @Override - public boolean isSelectable(T element) { - return element instanceof Level || element instanceof Measure; - } - - /** - * @see org.pivot4j.analytics.component.tree.NodeFilter#isVisible(org.olap4j.metadata.MetadataElement) - */ - @Override - public boolean isVisible(T element) { - if (element instanceof Level) { - Level level = (Level) element; - - if (level.getLevelType() == Level.Type.ALL || level.isCalculated()) { - return false; - } - } else if (element instanceof Measure) { - return !((Measure) element).isCalculated(); - } - - return true; - } - - /** - * @see org.pivot4j.analytics.component.tree.NodeFilter#isExpanded(org.olap4j.metadata.MetadataElement) - */ - @Override - public boolean isExpanded(T element) { - Dimension dimension = null; - - if (element instanceof Cube) { - return true; - } else if (element instanceof Dimension) { - dimension = (Dimension) element; - } else if (element instanceof Hierarchy) { - dimension = ((Hierarchy) element).getDimension(); - } - - if (dimension != null) { - try { - if (dimension.getDimensionType() == Dimension.Type.MEASURE) { - return true; - } - } catch (OlapException e) { - throw new FaceletException(e); - } - } - - return false; - } - - /** - * @see org.pivot4j.analytics.component.tree.NodeFilter#isActive(org.olap4j.metadata.MetadataElement) - */ - @Override - public boolean isActive(T element) { - return false; - } - - /** - * @return the stateManager - */ - public PivotStateManager getStateManager() { - return stateManager; - } - - /** - * @param stateManager - * the stateManager to set - */ - public void setStateManager(PivotStateManager stateManager) { - this.stateManager = stateManager; - } - - /** - * @return the table - */ - public DataTable getTable() { - return table; - } - - /** - * @param table - * the table to set - */ - public void setTable(DataTable table) { - this.table = table; - } +public class DrillThroughHandler implements NodeFilter, Serializable { + + @ManagedProperty(value = "#{pivotStateManager}") + private PivotStateManager stateManager; + + @ManagedProperty(value = "#{drillThroughData}") + private DrillThroughDataModel data; + + private CubeNode cubeNode; + + private TreeNode[] selection; + + private int maximumRows = 0; + + private DataTable table; + + public void update() { + update(data.getCell()); + } + + /** + * @param cell + */ + public void update(Cell cell) { + if (cell == null) { + throw new NullArgumentException("cell"); + } + + List elements = new LinkedList(); + + if (selection != null) { + for (TreeNode node : selection) { + MetadataElement elem = ((MetadataNode) node).getObject(); + elements.add(elem); + } + } + + data.setRowIndex(-1); + data.initialize(cell, elements, maximumRows); + + table.setFirst(0); + } + + public void reset() { + data.reset(); + + this.cubeNode = null; + this.selection = null; + this.maximumRows = 0; + } + + /** + * @return the cubeNode + */ + public CubeNode getCubeNode() { + if (cubeNode != null) { + return cubeNode; + } + + PivotModel model = stateManager.getModel(); + + if (model != null && model.isInitialized() && data.getCell() != null) { + this.cubeNode = new CubeNode(model.getCube()); + cubeNode.setNodeFilter(this); + } + + return cubeNode; + } + + /** + * @param cubeNode the cubeNode to set + */ + public void setCubeNode(CubeNode cubeNode) { + this.cubeNode = cubeNode; + } + + /** + * @return the data + */ + public DrillThroughDataModel getData() { + return data; + } + + /** + * @param data the data to set + */ + public void setData(DrillThroughDataModel data) { + this.data = data; + } + + /** + * @return the selection + */ + public TreeNode[] getSelection() { + return selection; + } + + /** + * @param newSelection the newSelection to set + */ + public void setSelection(TreeNode[] newSelection) { + if (newSelection == null) { + this.selection = null; + } else { + this.selection = Arrays.copyOf(newSelection, newSelection.length); + } + } + + /** + * @return the maximumRows + */ + public int getMaximumRows() { + return maximumRows; + } + + /** + * @param maximumRows the maximumRows to set + */ + public void setMaximumRows(int maximumRows) { + this.maximumRows = maximumRows; + } + + /** + * @see + * org.pivot4j.analytics.component.tree.NodeFilter#isSelected(org.olap4j.metadata.MetadataElement) + */ + @Override + public boolean isSelected(T element) { + return data.getSelection().contains(element); + } + + /** + * @see + * org.pivot4j.analytics.component.tree.NodeFilter#isSelectable(org.olap4j.metadata.MetadataElement) + */ + @Override + public boolean isSelectable(T element) { + return element instanceof Level || element instanceof Measure; + } + + /** + * @see + * org.pivot4j.analytics.component.tree.NodeFilter#isVisible(org.olap4j.metadata.MetadataElement) + */ + @Override + public boolean isVisible(T element) { + if (element instanceof Level) { + Level level = (Level) element; + + if (level.getLevelType() == Level.Type.ALL || level.isCalculated()) { + return false; + } + } else if (element instanceof Measure) { + return !((Measure) element).isCalculated(); + } + + return true; + } + + /** + * @see + * org.pivot4j.analytics.component.tree.NodeFilter#isExpanded(org.olap4j.metadata.MetadataElement) + */ + @Override + public boolean isExpanded(T element) { + Dimension dimension = null; + + if (element instanceof Cube) { + return true; + } else if (element instanceof Dimension) { + dimension = (Dimension) element; + } else if (element instanceof Hierarchy) { + dimension = ((Hierarchy) element).getDimension(); + } + + if (dimension != null) { + try { + if (dimension.getDimensionType() == Dimension.Type.MEASURE) { + return true; + } + } catch (OlapException e) { + throw new FaceletException(e); + } + } + + return false; + } + + /** + * @see + * org.pivot4j.analytics.component.tree.NodeFilter#isActive(org.olap4j.metadata.MetadataElement) + */ + @Override + public boolean isActive(T element) { + return false; + } + + /** + * @return the stateManager + */ + public PivotStateManager getStateManager() { + return stateManager; + } + + /** + * @param stateManager the stateManager to set + */ + public void setStateManager(PivotStateManager stateManager) { + this.stateManager = stateManager; + } + + /** + * @return the table + */ + public DataTable getTable() { + return table; + } + + /** + * @param table the table to set + */ + public void setTable(DataTable table) { + this.table = table; + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/FilterHandler.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/FilterHandler.java index a7ff4693..a547934c 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/FilterHandler.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/FilterHandler.java @@ -39,9 +39,9 @@ import org.pivot4j.transform.ChangeSlicer; import org.pivot4j.util.MemberHierarchyCache; import org.pivot4j.util.MemberSelection; +import org.primefaces.PrimeFaces; import org.primefaces.component.commandbutton.CommandButton; import org.primefaces.component.commandlink.CommandLink; -import org.primefaces.context.RequestContext; import org.primefaces.event.DragDropEvent; import org.primefaces.event.NodeSelectEvent; import org.primefaces.event.NodeUnselectEvent; @@ -51,580 +51,581 @@ @RequestScoped public class FilterHandler implements ModelChangeListener, NodeFilter { - @ManagedProperty(value = "#{pivotStateManager.model}") - private PivotModel model; - - @ManagedProperty(value = "#{navigatorHandler}") - private NavigatorHandler navigator; - - private TreeNode filterNode; - - private TreeNode[] selection; - - private MemberSelection filterMembers; - - private UIComponent filterPanel; - - private CommandButton buttonApply; - - @PostConstruct - protected void initialize() { - if (model != null) { - model.addModelChangeListener(this); - } - } - - @PreDestroy - protected void destroy() { - if (model != null) { - model.removeModelChangeListener(this); - } - } - - /** - * @return the model - */ - public PivotModel getModel() { - return model; - } - - /** - * @param model - * the model to set - */ - public void setModel(PivotModel model) { - this.model = model; - } - - /** - * @return the navigator - */ - public NavigatorHandler getNavigator() { - return navigator; - } - - /** - * @param navigator - * the navigator to set - */ - public void setNavigator(NavigatorHandler navigator) { - this.navigator = navigator; - } - - protected MemberSelection getFilteredMembers() { - if (filterMembers == null) { - Hierarchy hierarchy = getHierarchy(); - - if (hierarchy != null) { - ChangeSlicer transform = model.getTransform(ChangeSlicer.class); - - this.filterMembers = new MemberSelection( - transform.getSlicer(hierarchy), model.getCube()); - - if (model instanceof PivotModelImpl) { - MemberHierarchyCache cache = ((PivotModelImpl) model) - .getMemberHierarchyCache(); - filterMembers.setMemberHierarchyCache(cache); - } - } - - } - - return filterMembers; - } - - /** - * @return the filterNode - */ - public TreeNode getFilterNode() { - if (model != null && model.isInitialized()) { - Hierarchy hierarchy = getHierarchy(); - - if (filterNode == null && hierarchy != null) { - this.filterNode = new DefaultTreeNode(); - - filterNode.setExpanded(true); - - List members; - boolean isMeasure; - - try { - members = hierarchy.getRootMembers(); - isMeasure = hierarchy.getDimension().getDimensionType() == Type.MEASURE; - } catch (OlapException e) { - throw new FacesException(e); - } - - for (Member member : members) { - if (isMeasure && !member.isVisible()) { - continue; - } - - MemberNode node = new MemberNode(member); - - node.setNodeFilter(this); - node.setExpanded(true); - node.setSelectable(true); - node.setSelected(isSelected(member)); - - filterNode.getChildren().add(node); - } - - List initialSelection = ((DefaultTreeNode) filterNode) - .collectNodes(new NodeCollector() { - - @Override - public boolean collectNode(TreeNode node) { - return node.isSelected(); - } - - @Override - public boolean searchNode(TreeNode node) { - return node.isExpanded(); - } - }); - - this.selection = initialSelection - .toArray(new TreeNode[initialSelection.size()]); - } - } else { - this.filterNode = null; - } - - return filterNode; - } - - /** - * @param filterNode - * the filterNode to set - */ - public void setFilterNode(TreeNode filterNode) { - this.filterNode = filterNode; - } - - /** - * @return the selection - */ - public TreeNode[] getSelection() { - return selection; - } - - /** - * @param newSelection - * the selection to set - */ - public void setSelection(TreeNode[] newSelection) { - if (newSelection == null) { - this.selection = null; - } else { - this.selection = Arrays.copyOf(newSelection, newSelection.length); - } - } - - /** - * @return the filterPanel - */ - public UIComponent getFilterPanel() { - return filterPanel; - } - - /** - * @param filterPanel - * the filterPanel to set - */ - public void setFilterPanel(UIComponent filterPanel) { - this.filterPanel = filterPanel; - } - - /** - * @return the filteredHierarchy - */ - protected String getHierarchyName() { - FacesContext context = FacesContext.getCurrentInstance(); - UIViewRoot view = context.getViewRoot(); - - return (String) view.getAttributes().get("hierarchy"); - } - - /** - * @param hierarchyName - */ - protected void setHierarchyName(String hierarchyName) { - FacesContext context = FacesContext.getCurrentInstance(); - UIViewRoot view = context.getViewRoot(); - - if (hierarchyName == null) { - view.getAttributes().remove("hierarchy"); - } else { - view.getAttributes().put("hierarchy", hierarchyName); - } - - this.filterMembers = null; - this.filterNode = null; - this.selection = null; - } - - protected Hierarchy getHierarchy() { - String hierarchyName = getHierarchyName(); - - if (hierarchyName != null) { - return model.getCube().getHierarchies().get(hierarchyName); - } - - return null; - } - - /** - * @return the buttonApply - */ - public CommandButton getButtonApply() { - return buttonApply; - } - - /** - * @param buttonApply - * the buttonApply to set - */ - public void setButtonApply(CommandButton buttonApply) { - this.buttonApply = buttonApply; - } - - /** - * @param id - * @return - */ - protected List getNodePath(String id) { - // there should be a cleaner way to get data from the dropped component. - // it's a limitation on PFs' side : - // http://code.google.com/p/primefaces/issues/detail?id=2781 - String[] segments = id.split(":"); - String[] indexSegments = segments[segments.length - 2].split("_"); - - List path = new ArrayList(indexSegments.length); - for (String index : indexSegments) { - path.add(Integer.parseInt(index)); - } - - return path; - } - - /** - * @param id - * @return - */ - protected boolean isSourceNode(String id) { - return id.startsWith("source-tree-form:cube-navigator"); - } - - /** - * @param e - */ - public void onNodeSelected(NodeSelectEvent e) { - buttonApply.setDisabled(false); - } - - /** - * @param e - */ - public void onNodeUnselected(NodeUnselectEvent e) { - buttonApply.setDisabled(false); - } - - public void onClose() { - ChangeSlicer transform = model.getTransform(ChangeSlicer.class); - - Hierarchy hierarchy = getHierarchy(); - - if (!transform.getHierarchies().contains(hierarchy)) { - removeHierarchy(getHierarchyName()); - } - - setHierarchyName(null); - } - - /** - * @param e - */ - public void onDrop(DragDropEvent e) { - List sourcePath = getNodePath(e.getDragId()); - - Hierarchy hierarchy = null; - - if (isSourceNode(e.getDragId())) { - TreeNode sourceNode = findNodeFromPath(navigator.getCubeNode(), - sourcePath); - - if (sourceNode instanceof HierarchyNode) { - HierarchyNode node = (HierarchyNode) sourceNode; - hierarchy = node.getObject(); - } else if (sourceNode instanceof LevelNode) { - LevelNode node = (LevelNode) sourceNode; - Level level = node.getObject(); - - hierarchy = level.getHierarchy(); - } - - if (hierarchy == null) { - return; - } - - if (navigator.isSelected(hierarchy)) { - FacesContext context = FacesContext.getCurrentInstance(); - - ResourceBundle bundle = context.getApplication() - .getResourceBundle(context, "msg"); - - String title = bundle.getString("error.filter.title"); - String message = bundle.getString("error.filter.message"); - - context.addMessage(null, new FacesMessage( - FacesMessage.SEVERITY_WARN, title, message)); - return; - } - - UIComponent panel = createFilterItem(hierarchy); - filterPanel.getChildren().add(panel); - - show(hierarchy.getName()); - - RequestContext.getCurrentInstance().execute("PF('filterDialog').show();"); - } - } - - protected void configureFilter() { - if (model != null && filterPanel != null) { - filterPanel.getChildren().clear(); - - if (model.isInitialized()) { - ChangeSlicer transform = model.getTransform(ChangeSlicer.class); - - List hierarchies = transform.getHierarchies(); - - for (Hierarchy hierarchy : hierarchies) { - UIComponent panel = createFilterItem(hierarchy); - filterPanel.getChildren().add(panel); - } - } - } - } - - /** - * @param hierarchy - * @return - */ - protected UIComponent createFilterItem(Hierarchy hierarchy) { - String id = "filter-item-" + hierarchy.getUniqueName().hashCode(); + @ManagedProperty(value = "#{pivotStateManager.model}") + private PivotModel model; + + @ManagedProperty(value = "#{navigatorHandler}") + private NavigatorHandler navigator; + + private TreeNode filterNode; + + private TreeNode[] selection; - HtmlPanelGroup panel = new HtmlPanelGroup(); - panel.setId(id); - panel.setLayout("block"); - panel.setStyleClass("ui-widget-header filter-item"); + private MemberSelection filterMembers; + + private UIComponent filterPanel; - CommandLink link = new CommandLink(); - link.setId(id + "-link"); - link.setValue(hierarchy.getCaption()); - link.setTitle(hierarchy.getUniqueName()); + private CommandButton buttonApply; + + @PostConstruct + protected void initialize() { + if (model != null) { + model.addModelChangeListener(this); + } + } + + @PreDestroy + protected void destroy() { + if (model != null) { + model.removeModelChangeListener(this); + } + } + + /** + * @return the model + */ + public PivotModel getModel() { + return model; + } + + /** + * @param model the model to set + */ + public void setModel(PivotModel model) { + this.model = model; + } + + /** + * @return the navigator + */ + public NavigatorHandler getNavigator() { + return navigator; + } + + /** + * @param navigator the navigator to set + */ + public void setNavigator(NavigatorHandler navigator) { + this.navigator = navigator; + } + + protected MemberSelection getFilteredMembers() { + if (filterMembers == null) { + Hierarchy hierarchy = getHierarchy(); + + if (hierarchy != null) { + ChangeSlicer transform = model.getTransform(ChangeSlicer.class); + + this.filterMembers = new MemberSelection( + transform.getSlicer(hierarchy), model.getCube()); + + if (model instanceof PivotModelImpl) { + MemberHierarchyCache cache = ((PivotModelImpl) model) + .getMemberHierarchyCache(); + filterMembers.setMemberHierarchyCache(cache); + } + } + + } + + return filterMembers; + } + + /** + * @return the filterNode + */ + public TreeNode getFilterNode() { + if (model != null && model.isInitialized()) { + Hierarchy hierarchy = getHierarchy(); + + if (filterNode == null && hierarchy != null) { + this.filterNode = new DefaultTreeNode(); + + filterNode.setExpanded(true); + + List members; + boolean isMeasure; + + try { + members = hierarchy.getRootMembers(); + isMeasure = hierarchy.getDimension().getDimensionType() == Type.MEASURE; + } catch (OlapException e) { + throw new FacesException(e); + } + + for (Member member : members) { + if (isMeasure && !member.isVisible()) { + continue; + } + + MemberNode node = new MemberNode(member); + + node.setNodeFilter(this); + node.setExpanded(true); + node.setSelectable(true); + node.setSelected(isSelected(member)); + + filterNode.getChildren().add(node); + } + + List initialSelection = ((DefaultTreeNode) filterNode) + .collectNodes(new NodeCollector() { + + @Override + public boolean collectNode(TreeNode node) { + return node.isSelected(); + } + + @Override + public boolean searchNode(TreeNode node) { + return node.isExpanded(); + } + }); + + this.selection = initialSelection + .toArray(new TreeNode[initialSelection.size()]); + } + } else { + this.filterNode = null; + } + + return filterNode; + } + + /** + * @param filterNode the filterNode to set + */ + public void setFilterNode(TreeNode filterNode) { + this.filterNode = filterNode; + } + + /** + * @return the selection + */ + public TreeNode[] getSelection() { + return selection; + } + + /** + * @param newSelection the selection to set + */ + public void setSelection(TreeNode[] newSelection) { + if (newSelection == null) { + this.selection = null; + } else { + this.selection = Arrays.copyOf(newSelection, newSelection.length); + } + } + + /** + * @return the filterPanel + */ + public UIComponent getFilterPanel() { + return filterPanel; + } + + /** + * @param filterPanel the filterPanel to set + */ + public void setFilterPanel(UIComponent filterPanel) { + this.filterPanel = filterPanel; + } + + /** + * @return the filteredHierarchy + */ + protected String getHierarchyName() { + FacesContext context = FacesContext.getCurrentInstance(); + UIViewRoot view = context.getViewRoot(); + + return (String) view.getAttributes().get("hierarchy"); + } + + /** + * @param hierarchyName + */ + protected void setHierarchyName(String hierarchyName) { + FacesContext context = FacesContext.getCurrentInstance(); + UIViewRoot view = context.getViewRoot(); + + if (hierarchyName == null) { + view.getAttributes().remove("hierarchy"); + } else { + view.getAttributes().put("hierarchy", hierarchyName); + } + + this.filterMembers = null; + this.filterNode = null; + this.selection = null; + } + + protected Hierarchy getHierarchy() { + String hierarchyName = getHierarchyName(); + + if (hierarchyName != null) { + return model.getCube().getHierarchies().get(hierarchyName); + } + + return null; + } + + /** + * @return the buttonApply + */ + public CommandButton getButtonApply() { + return buttonApply; + } + + /** + * @param buttonApply the buttonApply to set + */ + public void setButtonApply(CommandButton buttonApply) { + this.buttonApply = buttonApply; + } + + /** + * @param id + * @return + */ + protected List getNodePath(String id) { + // there should be a cleaner way to get data from the dropped component. + // it's a limitation on PFs' side : + // http://code.google.com/p/primefaces/issues/detail?id=2781 + String[] segments = id.split(":"); + String[] indexSegments = segments[segments.length - 2].split("_"); + + List path = new ArrayList(indexSegments.length); + for (String index : indexSegments) { + path.add(Integer.parseInt(index)); + } + + return path; + } + + /** + * @param id + * @return + */ + protected boolean isSourceNode(String id) { + return id.startsWith("source-tree-form:cube-navigator"); + } + + /** + * @param e + */ + public void onNodeSelected(NodeSelectEvent e) { + buttonApply.setDisabled(false); + } + + /** + * @param e + */ + public void onNodeUnselected(NodeUnselectEvent e) { + buttonApply.setDisabled(false); + } + + public void onClose() { + ChangeSlicer transform = model.getTransform(ChangeSlicer.class); + + Hierarchy hierarchy = getHierarchy(); + + if (!transform.getHierarchies().contains(hierarchy)) { + removeHierarchy(getHierarchyName()); + } + + setHierarchyName(null); + } + + /** + * @param e + */ + public void onDrop(DragDropEvent e) { + List sourcePath = getNodePath(e.getDragId()); + + Hierarchy hierarchy = null; + + if (isSourceNode(e.getDragId())) { + TreeNode sourceNode = findNodeFromPath(navigator.getCubeNode(), + sourcePath); + + if (sourceNode instanceof HierarchyNode) { + HierarchyNode node = (HierarchyNode) sourceNode; + hierarchy = node.getObject(); + } else if (sourceNode instanceof LevelNode) { + LevelNode node = (LevelNode) sourceNode; + Level level = node.getObject(); + + hierarchy = level.getHierarchy(); + } + + if (hierarchy == null) { + return; + } + + if (navigator.isSelected(hierarchy)) { + FacesContext context = FacesContext.getCurrentInstance(); + + ResourceBundle bundle = context.getApplication() + .getResourceBundle(context, "msg"); + + String title = bundle.getString("error.filter.title"); + String message = bundle.getString("error.filter.message"); + + context.addMessage(null, new FacesMessage( + FacesMessage.SEVERITY_WARN, title, message)); + return; + } + + UIComponent panel = createFilterItem(hierarchy); + filterPanel.getChildren().add(panel); + + show(hierarchy.getName()); + + PrimeFaces.current().executeScript("PF('filterDialog').show();"); + } + } + + protected void configureFilter() { + if (model != null && filterPanel != null) { + filterPanel.getChildren().clear(); + + if (model.isInitialized()) { + ChangeSlicer transform = model.getTransform(ChangeSlicer.class); + + List hierarchies = transform.getHierarchies(); + + for (Hierarchy hierarchy : hierarchies) { + UIComponent panel = createFilterItem(hierarchy); + filterPanel.getChildren().add(panel); + } + } + } + } + + /** + * @param hierarchy + * @return + */ + protected UIComponent createFilterItem(Hierarchy hierarchy) { + String id = "filter-item-" + hierarchy.getUniqueName().hashCode(); - FacesContext context = FacesContext.getCurrentInstance(); - ExpressionFactory factory = context.getApplication() - .getExpressionFactory(); + HtmlPanelGroup panel = new HtmlPanelGroup(); + panel.setId(id); + panel.setLayout("block"); + panel.setStyleClass("ui-widget-header filter-item"); - link.setActionExpression(factory.createMethodExpression( - context.getELContext(), "#{filterHandler.show}", Void.class, - new Class[0])); - link.setUpdate(":filter-form"); - link.setOncomplete("PF('filterDialog').show();"); + CommandLink link = new CommandLink(); + link.setId(id + "-link"); + link.setValue(hierarchy.getCaption()); + link.setTitle(hierarchy.getUniqueName()); - UIParameter parameter = new UIParameter(); - parameter.setName("hierarchy"); - parameter.setValue(hierarchy.getName()); + FacesContext context = FacesContext.getCurrentInstance(); + ExpressionFactory factory = context.getApplication() + .getExpressionFactory(); - link.getChildren().add(parameter); + link.setActionExpression(factory.createMethodExpression( + context.getELContext(), "#{filterHandler.show}", Void.class, + new Class[0])); + link.setUpdate(":filter-form"); + link.setOncomplete("PF('filterDialog').show();"); - panel.getChildren().add(link); + UIParameter parameter = new UIParameter(); + parameter.setName("hierarchy"); + parameter.setValue(hierarchy.getName()); - CommandButton closeButton = new CommandButton(); - closeButton.setId(id + "-button"); - closeButton.setIcon("ui-icon-close"); - closeButton.setActionExpression(factory.createMethodExpression( - context.getELContext(), "#{filterHandler.removeHierarchy}", - Void.class, new Class[0])); - closeButton - .setUpdate(":filter-items-form,:source-tree-form,:grid-form,:editor-form:mdx-editor,:editor-form:editor-toolbar"); - closeButton.setOncomplete("onViewChanged()"); - - UIParameter parameter2 = new UIParameter(); - parameter2.setName("hierarchy"); - parameter2.setValue(hierarchy.getName()); - - closeButton.getChildren().add(parameter2); - - panel.getChildren().add(closeButton); - - return panel; - } - - public String getFilterItemId() { - String hierarchyName = getHierarchyName(); - - if (hierarchyName == null) { - return null; - } - - return ":filter-item-" - + hierarchyName.replaceAll("[\\[\\]]", "") - .replaceAll("[\\s\\.]", "_").toLowerCase(); - } - - public void onPreRenderView() { - FacesContext context = FacesContext.getCurrentInstance(); - - if (!context.isPostback()) { - configureFilter(); - } - } - - public void show() { - FacesContext context = FacesContext.getCurrentInstance(); - - Map parameters = context.getExternalContext() - .getRequestParameterMap(); - - String hierarchyName = parameters.get("hierarchy"); - show(hierarchyName); - } - - /** - * @param hierarchyName - */ - public void show(String hierarchyName) { - setHierarchyName(hierarchyName); - - buttonApply.setDisabled(true); - } - - public void apply() { - List members = null; - - if (selection != null) { - members = new ArrayList(selection.length); - - for (TreeNode node : selection) { - MemberNode memberNode = (MemberNode) node; - members.add(memberNode.getObject()); - } - } - - ChangeSlicer transform = model.getTransform(ChangeSlicer.class); - transform.setSlicer(getHierarchy(), members); - } - - public void removeHierarchy() { - FacesContext context = FacesContext.getCurrentInstance(); - - Map parameters = context.getExternalContext() - .getRequestParameterMap(); - - String hierarchyName = parameters.get("hierarchy"); - removeHierarchy(hierarchyName); - } - - /** - * @param hierarchyName - */ - public void removeHierarchy(String hierarchyName) { - Hierarchy hierarchy = model.getCube().getHierarchies() - .get(hierarchyName); - - ChangeSlicer transform = model.getTransform(ChangeSlicer.class); - transform.setSlicer(hierarchy, null); - - configureFilter(); - } - - /** - * @param parent - * @param indexes - * @return - */ - protected TreeNode findNodeFromPath(TreeNode parent, List indexes) { - if (indexes.size() > 1) { - return findNodeFromPath(parent.getChildren().get(indexes.get(0)), - indexes.subList(1, indexes.size())); - } else { - return parent.getChildren().get(indexes.get(0)); - } - } - - /** - * @see org.pivot4j.ModelChangeListener#modelInitialized(org.pivot4j.ModelChangeEvent) - */ - @Override - public void modelInitialized(ModelChangeEvent e) { - configureFilter(); - } - - /** - * @see org.pivot4j.ModelChangeListener#modelDestroyed(org.pivot4j.ModelChangeEvent) - */ - @Override - public void modelDestroyed(ModelChangeEvent e) { - } - - /** - * @see org.pivot4j.ModelChangeListener#modelChanged(org.pivot4j.ModelChangeEvent) - */ - @Override - public void modelChanged(ModelChangeEvent e) { - } - - /** - * @see org.pivot4j.ModelChangeListener#structureChanged(org.pivot4j.ModelChangeEvent) - */ - @Override - public void structureChanged(ModelChangeEvent e) { - configureFilter(); - } - - /** - * @param element - * @return - */ - @Override - public boolean isSelected(T element) { - return getFilteredMembers().isSelected((Member) element); - } - - /** - * @param element - * @return - */ - @Override - public boolean isSelectable(T element) { - return true; - } - - /** - * @see org.pivot4j.analytics.component.tree.NodeFilter#isActive(org.olap4j.metadata.MetadataElement) - */ - @Override - public boolean isActive(T element) { - return false; - } - - /** - * @see org.pivot4j.analytics.component.tree.NodeFilter#isVisible(org.olap4j.metadata.MetadataElement) - */ - @Override - public boolean isVisible(T element) { - return true; - } - - /** - * @see org.pivot4j.analytics.component.tree.NodeFilter#isExpanded(org.olap4j.metadata.MetadataElement) - */ - @Override - public boolean isExpanded(T element) { - return getFilteredMembers().findChild((Member) element) != null; - } + link.getChildren().add(parameter); + + panel.getChildren().add(link); + + CommandButton closeButton = new CommandButton(); + closeButton.setId(id + "-button"); + closeButton.setIcon("ui-icon-close"); + closeButton.setActionExpression(factory.createMethodExpression( + context.getELContext(), "#{filterHandler.removeHierarchy}", + Void.class, new Class[0])); + closeButton + .setUpdate(":filter-items-form,:source-tree-form,:grid-form,:editor-form:mdx-editor,:editor-form:editor-toolbar"); + closeButton.setOncomplete("onViewChanged()"); + + UIParameter parameter2 = new UIParameter(); + parameter2.setName("hierarchy"); + parameter2.setValue(hierarchy.getName()); + + closeButton.getChildren().add(parameter2); + + panel.getChildren().add(closeButton); + + return panel; + } + + public String getFilterItemId() { + String hierarchyName = getHierarchyName(); + + if (hierarchyName == null) { + return null; + } + + return ":filter-item-" + + hierarchyName.replaceAll("[\\[\\]]", "") + .replaceAll("[\\s\\.]", "_").toLowerCase(); + } + + public void onPreRenderView() { + FacesContext context = FacesContext.getCurrentInstance(); + + if (!context.isPostback()) { + configureFilter(); + } + } + + public void show() { + FacesContext context = FacesContext.getCurrentInstance(); + + Map parameters = context.getExternalContext() + .getRequestParameterMap(); + + String hierarchyName = parameters.get("hierarchy"); + show(hierarchyName); + } + + /** + * @param hierarchyName + */ + public void show(String hierarchyName) { + setHierarchyName(hierarchyName); + + buttonApply.setDisabled(true); + } + + public void apply() { + List members = null; + + if (selection != null) { + members = new ArrayList(selection.length); + + for (TreeNode node : selection) { + MemberNode memberNode = (MemberNode) node; + members.add(memberNode.getObject()); + } + } + + ChangeSlicer transform = model.getTransform(ChangeSlicer.class); + transform.setSlicer(getHierarchy(), members); + } + + public void removeHierarchy() { + FacesContext context = FacesContext.getCurrentInstance(); + + Map parameters = context.getExternalContext() + .getRequestParameterMap(); + + String hierarchyName = parameters.get("hierarchy"); + removeHierarchy(hierarchyName); + } + + /** + * @param hierarchyName + */ + public void removeHierarchy(String hierarchyName) { + Hierarchy hierarchy = model.getCube().getHierarchies() + .get(hierarchyName); + + ChangeSlicer transform = model.getTransform(ChangeSlicer.class); + transform.setSlicer(hierarchy, null); + + configureFilter(); + } + + /** + * @param parent + * @param indexes + * @return + */ + protected TreeNode findNodeFromPath(TreeNode parent, List indexes) { + if (indexes.size() > 1) { + return findNodeFromPath(parent.getChildren().get(indexes.get(0)), + indexes.subList(1, indexes.size())); + } else { + return parent.getChildren().get(indexes.get(0)); + } + } + + /** + * @see + * org.pivot4j.ModelChangeListener#modelInitialized(org.pivot4j.ModelChangeEvent) + */ + @Override + public void modelInitialized(ModelChangeEvent e) { + configureFilter(); + } + + /** + * @see + * org.pivot4j.ModelChangeListener#modelDestroyed(org.pivot4j.ModelChangeEvent) + */ + @Override + public void modelDestroyed(ModelChangeEvent e) { + } + + /** + * @see + * org.pivot4j.ModelChangeListener#modelChanged(org.pivot4j.ModelChangeEvent) + */ + @Override + public void modelChanged(ModelChangeEvent e) { + } + + /** + * @see + * org.pivot4j.ModelChangeListener#structureChanged(org.pivot4j.ModelChangeEvent) + */ + @Override + public void structureChanged(ModelChangeEvent e) { + configureFilter(); + } + + /** + * @param element + * @return + */ + @Override + public boolean isSelected(T element) { + return getFilteredMembers().isSelected((Member) element); + } + + /** + * @param element + * @return + */ + @Override + public boolean isSelectable(T element) { + return true; + } + + /** + * @see + * org.pivot4j.analytics.component.tree.NodeFilter#isActive(org.olap4j.metadata.MetadataElement) + */ + @Override + public boolean isActive(T element) { + return false; + } + + /** + * @see + * org.pivot4j.analytics.component.tree.NodeFilter#isVisible(org.olap4j.metadata.MetadataElement) + */ + @Override + public boolean isVisible(T element) { + return true; + } + + /** + * @see + * org.pivot4j.analytics.component.tree.NodeFilter#isExpanded(org.olap4j.metadata.MetadataElement) + */ + @Override + public boolean isExpanded(T element) { + return getFilteredMembers().findChild((Member) element) != null; + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/LayoutOption.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/LayoutOption.java new file mode 100644 index 00000000..8a14c7ca --- /dev/null +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/LayoutOption.java @@ -0,0 +1,58 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.pivot4j.analytics.ui; + +import java.io.Serializable; +import javax.faces.bean.ManagedBean; +import javax.faces.bean.SessionScoped; + +/** + * + * @author Judilson + */ +@ManagedBean(name = "layoutOption") +@SessionScoped +public class LayoutOption implements Serializable{ + + private Boolean enableTheme; + private Boolean enableMdx; + + public void changeOptionTheme() { + + if (enableMdx) { + setEnableMdx(true); + } else { + setEnableMdx(false); + } + + } + + public void changeOptionMdx() { + + if (enableMdx) { + setEnableMdx(true); + } else { + setEnableMdx(false); + } + + } + + public Boolean getEnableTheme() { + return enableTheme; + } + + public void setEnableTheme(Boolean enableTheme) { + this.enableTheme = enableTheme; + } + + public Boolean getEnableMdx() { + return enableMdx; + } + + public void setEnableMdx(Boolean enableMdx) { + this.enableMdx = enableMdx; + } +} diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/LayoutRegion.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/LayoutRegion.java index 4110a984..89841dde 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/LayoutRegion.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/LayoutRegion.java @@ -2,5 +2,5 @@ public enum LayoutRegion { - Navigator, Content, Mdx, Filter + Navigator, Content, Mdx, Filter } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/MemberSelectionHandler.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/MemberSelectionHandler.java index 1afdee2c..1e62deae 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/MemberSelectionHandler.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/MemberSelectionHandler.java @@ -38,697 +38,688 @@ @ViewScoped public class MemberSelectionHandler implements NodeFilter, Serializable { - private static final long serialVersionUID = -2124965576827229229L; + private static final long serialVersionUID = -2124965576827229229L; - @ManagedProperty(value = "#{pivotStateManager.model}") - private PivotModel model; + @ManagedProperty(value = "#{pivotStateManager.model}") + private PivotModel model; - private TreeNode sourceNode; + private TreeNode sourceNode; - private TreeNode targetNode; + private TreeNode targetNode; - private TreeNode[] sourceSelection; + private TreeNode[] sourceSelection; - private TreeNode[] targetSelection; + private TreeNode[] targetSelection; - private Hierarchy hierarchy; + private Hierarchy hierarchy; - private String hierarchyName; + private String hierarchyName; - private CommandButton buttonAdd; + private CommandButton buttonAdd; - private CommandButton buttonRemove; + private CommandButton buttonRemove; - private CommandButton buttonUp; + private CommandButton buttonUp; - private CommandButton buttonDown; + private CommandButton buttonDown; - private CommandButton buttonApply; + private CommandButton buttonApply; - private CommandButton buttonOk; + private CommandButton buttonOk; - private MemberSelection selection; + private MemberSelection selection; - @PostConstruct - protected void initialize() { - } + @PostConstruct + protected void initialize() { + } - @PreDestroy - protected void destroy() { - } + @PreDestroy + protected void destroy() { + } - /** - * @return the model - */ - public PivotModel getModel() { - return model; - } + /** + * @return the model + */ + public PivotModel getModel() { + return model; + } - /** - * @param model - * the model to set - */ - public void setModel(PivotModel model) { - this.model = model; - } + /** + * @param model the model to set + */ + public void setModel(PivotModel model) { + this.model = model; + } - /** - * @return the sourceNode - */ - public TreeNode getSourceNode() { - if (sourceNode == null) { - this.sourceNode = new DefaultTreeNode(); + /** + * @return the sourceNode + */ + public TreeNode getSourceNode() { + if (sourceNode == null) { + this.sourceNode = new DefaultTreeNode(); - Hierarchy hier = getHierarchy(); - if (hier != null) { - try { - boolean isMeasure = hierarchy.getDimension() - .getDimensionType() == Type.MEASURE; + Hierarchy hier = getHierarchy(); + if (hier != null) { + try { + boolean isMeasure = hierarchy.getDimension() + .getDimensionType() == Type.MEASURE; - List members = hier.getRootMembers(); + List members = hier.getRootMembers(); - for (Member member : members) { - if (isMeasure && !member.isVisible()) { - continue; - } + for (Member member : members) { + if (isMeasure && !member.isVisible()) { + continue; + } - MemberNode node = new MemberNode(member); - node.setNodeFilter(this); + MemberNode node = new MemberNode(member); + node.setNodeFilter(this); - if (isVisible(member)) { - node.setExpanded(isExpanded(member)); - node.setSelectable(isSelectable(member)); - node.setSelected(isSelected(member)); - node.getData().setSelected(isActive(member)); + if (isVisible(member)) { + node.setExpanded(isExpanded(member)); + node.setSelectable(isSelectable(member)); + node.setSelected(isSelected(member)); + node.getData().setSelected(isActive(member)); - sourceNode.getChildren().add(node); - } - } - } catch (OlapException e) { - throw new FacesException(e); - } - } - } + sourceNode.getChildren().add(node); + } + } + } catch (OlapException e) { + throw new FacesException(e); + } + } + } - return sourceNode; - } + return sourceNode; + } - /** - * @param sourceNode - * the sourceNode to set - */ - public void setSourceNode(TreeNode sourceNode) { - this.sourceNode = sourceNode; - } + /** + * @param sourceNode the sourceNode to set + */ + public void setSourceNode(TreeNode sourceNode) { + this.sourceNode = sourceNode; + } - /** - * @return the targetNode - */ - public TreeNode getTargetNode() { - if (targetNode == null) { - MemberSelection sel = getSelection(); + /** + * @return the targetNode + */ + public TreeNode getTargetNode() { + if (targetNode == null) { + MemberSelection sel = getSelection(); - if (sel != null) { - this.targetNode = new SelectionNode(sel); + if (sel != null) { + this.targetNode = new SelectionNode(sel); - targetNode.setExpanded(true); - } - } - - return targetNode; - } - - /** - * @param targetNode - * the targetNode to set - */ - public void setTargetNode(TreeNode targetNode) { - this.targetNode = targetNode; - } - - public void show() { - reset(); - - FacesContext context = FacesContext.getCurrentInstance(); - - Map parameters = context.getExternalContext() - .getRequestParameterMap(); - - this.hierarchyName = parameters.get("hierarchy"); - } - - public void reset() { - buttonAdd.setDisabled(true); - buttonRemove.setDisabled(true); - buttonUp.setDisabled(true); - buttonDown.setDisabled(true); - buttonApply.setDisabled(true); - buttonOk.setDisabled(true); - - this.hierarchyName = null; - this.hierarchy = null; - this.sourceNode = null; - this.targetNode = null; - this.selection = null; - } - - public void apply() { - PlaceMembersOnAxes transform = model - .getTransform(PlaceMembersOnAxes.class); - transform.placeMembers(getHierarchy(), getSelection().getMembers()); - - buttonApply.setDisabled(true); - buttonOk.setDisabled(true); - } - - public void add() { - FacesContext context = FacesContext.getCurrentInstance(); - - Map parameters = context.getExternalContext() - .getRequestParameterMap(); - - String modeName = parameters.get("mode"); - - if (modeName == null) { - modeName = SelectionMode.Single.name(); - } - - add(modeName); - } - - /** - * @param modeName - */ - public void add(String modeName) { - SelectionMode mode = null; - - if (modeName != null) { - mode = SelectionMode.valueOf(modeName); - } + targetNode.setExpanded(true); + } + } - MemberSelection sel = getSelection(); + return targetNode; + } + + /** + * @param targetNode the targetNode to set + */ + public void setTargetNode(TreeNode targetNode) { + this.targetNode = targetNode; + } + + public void show() { + reset(); + + FacesContext context = FacesContext.getCurrentInstance(); + + Map parameters = context.getExternalContext() + .getRequestParameterMap(); + + this.hierarchyName = parameters.get("hierarchy"); + } + + public void reset() { + buttonAdd.setDisabled(true); + buttonRemove.setDisabled(true); + buttonUp.setDisabled(true); + buttonDown.setDisabled(true); + buttonApply.setDisabled(true); + buttonOk.setDisabled(true); + + this.hierarchyName = null; + this.hierarchy = null; + this.sourceNode = null; + this.targetNode = null; + this.selection = null; + } + + public void apply() { + PlaceMembersOnAxes transform = model + .getTransform(PlaceMembersOnAxes.class); + transform.placeMembers(getHierarchy(), getSelection().getMembers()); + + buttonApply.setDisabled(true); + buttonOk.setDisabled(true); + } + + public void add() { + FacesContext context = FacesContext.getCurrentInstance(); + + Map parameters = context.getExternalContext() + .getRequestParameterMap(); + + String modeName = parameters.get("mode"); + + if (modeName == null) { + modeName = SelectionMode.Single.name(); + } + + add(modeName); + } + + /** + * @param modeName + */ + public void add(String modeName) { + SelectionMode mode = null; - if (mode == null) { - sel.clear(); - } else { - boolean empty = true; + if (modeName != null) { + mode = SelectionMode.valueOf(modeName); + } - List members = sel.getMembers(); + MemberSelection sel = getSelection(); - for (TreeNode node : sourceSelection) { - MemberNode memberNode = (MemberNode) node; + if (mode == null) { + sel.clear(); + } else { + boolean empty = true; - Member member = memberNode.getObject(); + List members = sel.getMembers(); - List targetMembers = mode.getTargetMembers(member); + for (TreeNode node : sourceSelection) { + MemberNode memberNode = (MemberNode) node; - for (Member target : targetMembers) { - if (!members.contains(target)) { - members.add(target); - empty = false; - } - } - } + Member member = memberNode.getObject(); - if (empty) { - FacesContext context = FacesContext.getCurrentInstance(); + List targetMembers = mode.getTargetMembers(member); - ResourceBundle bundle = context.getApplication() - .getResourceBundle(context, "msg"); + for (Member target : targetMembers) { + if (!members.contains(target)) { + members.add(target); + empty = false; + } + } + } - String title = bundle.getString("warn.noMembers.title"); - String message = bundle - .getString("warn.noMembers.select.message"); - FacesContext.getCurrentInstance().addMessage( - null, - new FacesMessage(FacesMessage.SEVERITY_WARN, title, - message)); - return; - } + if (empty) { + FacesContext context = FacesContext.getCurrentInstance(); - this.selection = new MemberSelection(members, model.getCube()); + ResourceBundle bundle = context.getApplication() + .getResourceBundle(context, "msg"); - if (model instanceof PivotModelImpl) { - MemberHierarchyCache cache = ((PivotModelImpl) model) - .getMemberHierarchyCache(); - selection.setMemberHierarchyCache(cache); - } - } + String title = bundle.getString("warn.noMembers.title"); + String message = bundle + .getString("warn.noMembers.select.message"); + FacesContext.getCurrentInstance().addMessage( + null, + new FacesMessage(FacesMessage.SEVERITY_WARN, title, + message)); + return; + } - this.sourceNode = null; - this.targetNode = null; + this.selection = new MemberSelection(members, model.getCube()); - this.sourceSelection = null; - this.targetSelection = null; + if (model instanceof PivotModelImpl) { + MemberHierarchyCache cache = ((PivotModelImpl) model) + .getMemberHierarchyCache(); + selection.setMemberHierarchyCache(cache); + } + } - updateButtonStatus(); + this.sourceNode = null; + this.targetNode = null; - buttonApply.setDisabled(false); - buttonOk.setDisabled(false); - } + this.sourceSelection = null; + this.targetSelection = null; - public void remove() { - FacesContext context = FacesContext.getCurrentInstance(); + updateButtonStatus(); - Map parameters = context.getExternalContext() - .getRequestParameterMap(); + buttonApply.setDisabled(false); + buttonOk.setDisabled(false); + } - String modeName = parameters.get("mode"); + public void remove() { + FacesContext context = FacesContext.getCurrentInstance(); - if (modeName == null) { - modeName = SelectionMode.Single.name(); - } + Map parameters = context.getExternalContext() + .getRequestParameterMap(); - remove(modeName); - } + String modeName = parameters.get("mode"); - /** - * @param modeName - */ - public void remove(String modeName) { - SelectionMode mode = null; + if (modeName == null) { + modeName = SelectionMode.Single.name(); + } - if (modeName != null) { - mode = SelectionMode.valueOf(modeName); - } + remove(modeName); + } - MemberSelection sel = getSelection(); + /** + * @param modeName + */ + public void remove(String modeName) { + SelectionMode mode = null; - if (mode == null) { - sel.clear(); - } else { - boolean empty = true; + if (modeName != null) { + mode = SelectionMode.valueOf(modeName); + } - List members = sel.getMembers(); + MemberSelection sel = getSelection(); - OlapUtils utils = new OlapUtils(model.getCube()); + if (mode == null) { + sel.clear(); + } else { + boolean empty = true; - if (model instanceof PivotModelImpl) { - utils.setMemberHierarchyCache(((PivotModelImpl) model) - .getMemberHierarchyCache()); - } + List members = sel.getMembers(); - for (TreeNode node : targetSelection) { - SelectionNode memberNode = (SelectionNode) node; + OlapUtils utils = new OlapUtils(model.getCube()); - Member member = memberNode.getObject(); + if (model instanceof PivotModelImpl) { + utils.setMemberHierarchyCache(((PivotModelImpl) model) + .getMemberHierarchyCache()); + } - List targetMembers = mode.getTargetMembers(member); + for (TreeNode node : targetSelection) { + SelectionNode memberNode = (SelectionNode) node; - for (Member target : targetMembers) { - Member wrappedMember = utils.wrapRaggedIfNecessary(target); + Member member = memberNode.getObject(); - if (members.contains(wrappedMember)) { - members.remove(wrappedMember); - empty = false; - } - } - } + List targetMembers = mode.getTargetMembers(member); - if (empty) { - FacesContext context = FacesContext.getCurrentInstance(); + for (Member target : targetMembers) { + Member wrappedMember = utils.wrapRaggedIfNecessary(target); - ResourceBundle bundle = context.getApplication() - .getResourceBundle(context, "msg"); + if (members.contains(wrappedMember)) { + members.remove(wrappedMember); + empty = false; + } + } + } - String title = bundle.getString("warn.noMembers.title"); - String message = bundle - .getString("warn.noMembers.remove.message"); - FacesContext.getCurrentInstance().addMessage( - null, - new FacesMessage(FacesMessage.SEVERITY_WARN, title, - message)); - return; - } + if (empty) { + FacesContext context = FacesContext.getCurrentInstance(); - this.selection = new MemberSelection(members, model.getCube()); + ResourceBundle bundle = context.getApplication() + .getResourceBundle(context, "msg"); - if (model instanceof PivotModelImpl) { - MemberHierarchyCache cache = ((PivotModelImpl) model) - .getMemberHierarchyCache(); - selection.setMemberHierarchyCache(cache); - } - } + String title = bundle.getString("warn.noMembers.title"); + String message = bundle + .getString("warn.noMembers.remove.message"); + FacesContext.getCurrentInstance().addMessage( + null, + new FacesMessage(FacesMessage.SEVERITY_WARN, title, + message)); + return; + } - this.sourceNode = null; - this.targetNode = null; + this.selection = new MemberSelection(members, model.getCube()); - this.sourceSelection = null; - this.targetSelection = null; + if (model instanceof PivotModelImpl) { + MemberHierarchyCache cache = ((PivotModelImpl) model) + .getMemberHierarchyCache(); + selection.setMemberHierarchyCache(cache); + } + } - updateButtonStatus(); + this.sourceNode = null; + this.targetNode = null; - buttonApply.setDisabled(false); - buttonOk.setDisabled(false); - } + this.sourceSelection = null; + this.targetSelection = null; - public void moveUp() { - SelectionNode node = (SelectionNode) targetSelection[0]; - Member member = node.getObject(); + updateButtonStatus(); - MemberSelection sel = getSelection(); - sel.moveUp(member); + buttonApply.setDisabled(false); + buttonOk.setDisabled(false); + } - SelectionNode parent = (SelectionNode) node.getParent(); - parent.moveUp(node); + public void moveUp() { + SelectionNode node = (SelectionNode) targetSelection[0]; + Member member = node.getObject(); - updateButtonStatus(); + MemberSelection sel = getSelection(); + sel.moveUp(member); - buttonApply.setDisabled(false); - buttonOk.setDisabled(false); - } + SelectionNode parent = (SelectionNode) node.getParent(); + parent.moveUp(node); - public void moveDown() { - SelectionNode node = (SelectionNode) targetSelection[0]; - Member member = node.getObject(); + updateButtonStatus(); - MemberSelection sel = getSelection(); - sel.moveDown(member); + buttonApply.setDisabled(false); + buttonOk.setDisabled(false); + } - SelectionNode parent = (SelectionNode) node.getParent(); - parent.moveDown(node); + public void moveDown() { + SelectionNode node = (SelectionNode) targetSelection[0]; + Member member = node.getObject(); - updateButtonStatus(); + MemberSelection sel = getSelection(); + sel.moveDown(member); - buttonApply.setDisabled(false); - buttonOk.setDisabled(false); - } + SelectionNode parent = (SelectionNode) node.getParent(); + parent.moveDown(node); - public Hierarchy getHierarchy() { - if (hierarchy == null && hierarchyName != null && model.isInitialized()) { - this.hierarchy = model.getCube().getHierarchies() - .get(hierarchyName); - } + updateButtonStatus(); - return hierarchy; - } + buttonApply.setDisabled(false); + buttonOk.setDisabled(false); + } - protected MemberSelection getSelection() { - if (selection == null) { - Hierarchy hier = getHierarchy(); + public Hierarchy getHierarchy() { + if (hierarchy == null && hierarchyName != null && model.isInitialized()) { + this.hierarchy = model.getCube().getHierarchies() + .get(hierarchyName); + } - if (hier != null) { - PlaceMembersOnAxes transform = model - .getTransform(PlaceMembersOnAxes.class); + return hierarchy; + } - List members = transform.findVisibleMembers(hier); - this.selection = new MemberSelection(members, model.getCube()); + protected MemberSelection getSelection() { + if (selection == null) { + Hierarchy hier = getHierarchy(); - if (model instanceof PivotModelImpl) { - MemberHierarchyCache cache = ((PivotModelImpl) model) - .getMemberHierarchyCache(); - selection.setMemberHierarchyCache(cache); - } - } - } - - return selection; - } - - public boolean isAddButtonEnabled() { - boolean canAdd; - - if (sourceSelection == null || sourceSelection.length == 0) { - canAdd = false; - } else { - canAdd = true; - - for (TreeNode node : sourceSelection) { - if (((MemberNode) node).getData().isSelected()) { - canAdd = false; - break; - } - } - } - - return canAdd; - } - - public boolean isRemoveButtonEnabled() { - boolean canRemove; - - if (targetSelection == null || targetSelection.length == 0) { - canRemove = false; - } else { - canRemove = true; - - for (TreeNode node : targetSelection) { - if (!((SelectionNode) node).getData().isSelected()) { - canRemove = false; - break; - } - } - } - - return canRemove; - } - - public boolean isUpButtonEnabled() { - boolean canMoveUp; - - if (targetSelection == null || targetSelection.length != 1) { - canMoveUp = false; - } else { - SelectionNode node = (SelectionNode) targetSelection[0]; - - Member member = node.getObject(); - - MemberSelection sel = getSelection(); - - canMoveUp = sel.canMoveUp(member); - } - - return canMoveUp; - } - - public boolean isDownButtonEnabled() { - boolean canMoveDown; - - if (targetSelection == null || targetSelection.length != 1) { - canMoveDown = false; - } else { - SelectionNode node = (SelectionNode) targetSelection[0]; - - Member member = node.getObject(); - - MemberSelection sel = getSelection(); - canMoveDown = sel.canMoveDown(member); - } - - return canMoveDown; - } - - /** - * @param e - */ - public void onSourceNodeSelected(NodeSelectEvent e) { - updateButtonStatus(); - } - - /** - * @param e - */ - public void onTargetNodeSelected(NodeSelectEvent e) { - updateButtonStatus(); - } - - protected void updateButtonStatus() { - buttonAdd.setDisabled(!isAddButtonEnabled()); - buttonRemove.setDisabled(!isRemoveButtonEnabled()); - buttonUp.setDisabled(!isUpButtonEnabled()); - buttonDown.setDisabled(!isDownButtonEnabled()); - } - - /** - * @return the hierarchyName - */ - public String getHierarchyName() { - return hierarchyName; - } - - /** - * @param hierarchyName - * the hierarchyName to set - */ - public void setHierarchyName(String hierarchyName) { - this.hierarchyName = hierarchyName; - } - - /** - * @return the sourceSelection - */ - public TreeNode[] getSourceSelection() { - return sourceSelection; - } - - /** - * @param newSelection - * the sourceSelection to set - */ - public void setSourceSelection(TreeNode[] newSelection) { - if (newSelection == null) { - this.sourceSelection = null; - } else { - this.sourceSelection = Arrays.copyOf(newSelection, - newSelection.length); - } - } - - /** - * @return the targetSelection - */ - public TreeNode[] getTargetSelection() { - return targetSelection; - } - - /** - * @param newSelection - * the targetSelection to set - */ - public void setTargetSelection(TreeNode[] newSelection) { - if (newSelection == null) { - this.targetSelection = null; - } else { - this.targetSelection = Arrays.copyOf(newSelection, - newSelection.length); - } - } - - /** - * @return the buttonAdd - */ - public CommandButton getButtonAdd() { - return buttonAdd; - } - - /** - * @param buttonAdd - * the buttonAdd to set - */ - public void setButtonAdd(CommandButton buttonAdd) { - this.buttonAdd = buttonAdd; - } - - /** - * @return the buttonRemove - */ - public CommandButton getButtonRemove() { - return buttonRemove; - } - - /** - * @param buttonRemove - * the buttonRemove to set - */ - public void setButtonRemove(CommandButton buttonRemove) { - this.buttonRemove = buttonRemove; - } - - /** - * @return the buttonUp - */ - public CommandButton getButtonUp() { - return buttonUp; - } - - /** - * @param buttonUp - * the buttonUp to set - */ - public void setButtonUp(CommandButton buttonUp) { - this.buttonUp = buttonUp; - } - - /** - * @return the buttonDown - */ - public CommandButton getButtonDown() { - return buttonDown; - } - - /** - * @param buttonDown - * the buttonDown to set - */ - public void setButtonDown(CommandButton buttonDown) { - this.buttonDown = buttonDown; - } - - /** - * @return the buttonApply - */ - public CommandButton getButtonApply() { - return buttonApply; - } - - /** - * @param buttonApply - * the buttonApply to set - */ - public void setButtonApply(CommandButton buttonApply) { - this.buttonApply = buttonApply; - } - - /** - * @return the buttonOk - */ - public CommandButton getButtonOk() { - return buttonOk; - } - - /** - * @param buttonOk - * the buttonOk to set - */ - public void setButtonOk(CommandButton buttonOk) { - this.buttonOk = buttonOk; - } - - /** - * @param element - * @return - */ - @Override - public boolean isSelected(T element) { - return false; - } - - /** - * @param element - * @return - */ - @Override - public boolean isSelectable(T element) { - return true; - } - - /** - * @see org.pivot4j.analytics.component.tree.NodeFilter#isVisible(org.olap4j.metadata.MetadataElement) - */ - @Override - public boolean isVisible(T element) { - Member member = (Member) element; - - try { - return !isActive(element) || member.getChildMemberCount() > 0; - } catch (OlapException e) { - throw new FacesException(e); - } - } - - /** - * @see org.pivot4j.analytics.component.tree.NodeFilter#isActive(org.olap4j.metadata.MetadataElement) - */ - @Override - public boolean isActive(T element) { - return getSelection().isSelected((Member) element); - } - - /** - * @see org.pivot4j.analytics.component.tree.NodeFilter#isExpanded(org.olap4j.metadata.MetadataElement) - */ - @Override - public boolean isExpanded(T element) { - return getSelection().findChild((Member) element) != null; - } + if (hier != null) { + PlaceMembersOnAxes transform = model + .getTransform(PlaceMembersOnAxes.class); + + List members = transform.findVisibleMembers(hier); + this.selection = new MemberSelection(members, model.getCube()); + + if (model instanceof PivotModelImpl) { + MemberHierarchyCache cache = ((PivotModelImpl) model) + .getMemberHierarchyCache(); + selection.setMemberHierarchyCache(cache); + } + } + } + + return selection; + } + + public boolean isAddButtonEnabled() { + boolean canAdd; + + if (sourceSelection == null || sourceSelection.length == 0) { + canAdd = false; + } else { + canAdd = true; + + for (TreeNode node : sourceSelection) { + if (((MemberNode) node).getData().isSelected()) { + canAdd = false; + break; + } + } + } + + return canAdd; + } + + public boolean isRemoveButtonEnabled() { + boolean canRemove; + + if (targetSelection == null || targetSelection.length == 0) { + canRemove = false; + } else { + canRemove = true; + + for (TreeNode node : targetSelection) { + if (!((SelectionNode) node).getData().isSelected()) { + canRemove = false; + break; + } + } + } + + return canRemove; + } + + public boolean isUpButtonEnabled() { + boolean canMoveUp; + + if (targetSelection == null || targetSelection.length != 1) { + canMoveUp = false; + } else { + SelectionNode node = (SelectionNode) targetSelection[0]; + + Member member = node.getObject(); + + MemberSelection sel = getSelection(); + + canMoveUp = sel.canMoveUp(member); + } + + return canMoveUp; + } + + public boolean isDownButtonEnabled() { + boolean canMoveDown; + + if (targetSelection == null || targetSelection.length != 1) { + canMoveDown = false; + } else { + SelectionNode node = (SelectionNode) targetSelection[0]; + + Member member = node.getObject(); + + MemberSelection sel = getSelection(); + canMoveDown = sel.canMoveDown(member); + } + + return canMoveDown; + } + + /** + * @param e + */ + public void onSourceNodeSelected(NodeSelectEvent e) { + updateButtonStatus(); + } + + /** + * @param e + */ + public void onTargetNodeSelected(NodeSelectEvent e) { + updateButtonStatus(); + } + + protected void updateButtonStatus() { + buttonAdd.setDisabled(!isAddButtonEnabled()); + buttonRemove.setDisabled(!isRemoveButtonEnabled()); + buttonUp.setDisabled(!isUpButtonEnabled()); + buttonDown.setDisabled(!isDownButtonEnabled()); + } + + /** + * @return the hierarchyName + */ + public String getHierarchyName() { + return hierarchyName; + } + + /** + * @param hierarchyName the hierarchyName to set + */ + public void setHierarchyName(String hierarchyName) { + this.hierarchyName = hierarchyName; + } + + /** + * @return the sourceSelection + */ + public TreeNode[] getSourceSelection() { + return sourceSelection; + } + + /** + * @param newSelection the sourceSelection to set + */ + public void setSourceSelection(TreeNode[] newSelection) { + if (newSelection == null) { + this.sourceSelection = null; + } else { + this.sourceSelection = Arrays.copyOf(newSelection, + newSelection.length); + } + } + + /** + * @return the targetSelection + */ + public TreeNode[] getTargetSelection() { + return targetSelection; + } + + /** + * @param newSelection the targetSelection to set + */ + public void setTargetSelection(TreeNode[] newSelection) { + if (newSelection == null) { + this.targetSelection = null; + } else { + this.targetSelection = Arrays.copyOf(newSelection, + newSelection.length); + } + } + + /** + * @return the buttonAdd + */ + public CommandButton getButtonAdd() { + return buttonAdd; + } + + /** + * @param buttonAdd the buttonAdd to set + */ + public void setButtonAdd(CommandButton buttonAdd) { + this.buttonAdd = buttonAdd; + } + + /** + * @return the buttonRemove + */ + public CommandButton getButtonRemove() { + return buttonRemove; + } + + /** + * @param buttonRemove the buttonRemove to set + */ + public void setButtonRemove(CommandButton buttonRemove) { + this.buttonRemove = buttonRemove; + } + + /** + * @return the buttonUp + */ + public CommandButton getButtonUp() { + return buttonUp; + } + + /** + * @param buttonUp the buttonUp to set + */ + public void setButtonUp(CommandButton buttonUp) { + this.buttonUp = buttonUp; + } + + /** + * @return the buttonDown + */ + public CommandButton getButtonDown() { + return buttonDown; + } + + /** + * @param buttonDown the buttonDown to set + */ + public void setButtonDown(CommandButton buttonDown) { + this.buttonDown = buttonDown; + } + + /** + * @return the buttonApply + */ + public CommandButton getButtonApply() { + return buttonApply; + } + + /** + * @param buttonApply the buttonApply to set + */ + public void setButtonApply(CommandButton buttonApply) { + this.buttonApply = buttonApply; + } + + /** + * @return the buttonOk + */ + public CommandButton getButtonOk() { + return buttonOk; + } + + /** + * @param buttonOk the buttonOk to set + */ + public void setButtonOk(CommandButton buttonOk) { + this.buttonOk = buttonOk; + } + + /** + * @param element + * @return + */ + @Override + public boolean isSelected(T element) { + return false; + } + + /** + * @param element + * @return + */ + @Override + public boolean isSelectable(T element) { + return true; + } + + /** + * @see + * org.pivot4j.analytics.component.tree.NodeFilter#isVisible(org.olap4j.metadata.MetadataElement) + */ + @Override + public boolean isVisible(T element) { + Member member = (Member) element; + + try { + return !isActive(element) || member.getChildMemberCount() > 0; + } catch (OlapException e) { + throw new FacesException(e); + } + } + + /** + * @see + * org.pivot4j.analytics.component.tree.NodeFilter#isActive(org.olap4j.metadata.MetadataElement) + */ + @Override + public boolean isActive(T element) { + return getSelection().isSelected((Member) element); + } + + /** + * @see + * org.pivot4j.analytics.component.tree.NodeFilter#isExpanded(org.olap4j.metadata.MetadataElement) + */ + @Override + public boolean isExpanded(T element) { + return getSelection().findChild((Member) element) != null; + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/NavigatorHandler.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/NavigatorHandler.java index a7131184..bd25dc8a 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/NavigatorHandler.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/NavigatorHandler.java @@ -46,792 +46,798 @@ @RequestScoped public class NavigatorHandler implements ModelChangeListener, NodeFilter { - @ManagedProperty(value = "#{pivotStateManager.model}") - private PivotModel model; - - private CubeNode cubeNode; - - private TreeNode targetNode; - - private List dimensions; - - private Map> hierarchies; - - private Map> levels; - - private Map> members; - - @PostConstruct - protected void initialize() { - if (model != null) { - model.addModelChangeListener(this); - } - } - - @PreDestroy - protected void destroy() { - if (model != null) { - model.removeModelChangeListener(this); - } - } - - /** - * @return the model - */ - public PivotModel getModel() { - return model; - } - - /** - * @param model - * the model to set - */ - public void setModel(PivotModel model) { - this.model = model; - } - - /** - * @param axis - * @return - */ - protected List getDimensions(Axis axis) { - if (dimensions == null) { - this.dimensions = new ArrayList(); - - for (Hierarchy hierarchy : getHierarchies(axis)) { - dimensions.add(hierarchy.getDimension()); - } - } - - return dimensions; - } - - /** - * @param axis - * @return - */ - protected List getHierarchies(Axis axis) { - if (hierarchies == null) { - this.hierarchies = new HashMap>(2); - } - - List result = hierarchies.get(axis); - if (result == null) { - if (axis.equals(Axis.FILTER)) { - ChangeSlicer transform = model.getTransform(ChangeSlicer.class); - result = transform.getHierarchies(); - } else { - PlaceHierarchiesOnAxes transform = model - .getTransform(PlaceHierarchiesOnAxes.class); - result = transform.findVisibleHierarchies(axis); - } - - hierarchies.put(axis, result); - } - - return result; - } - - /** - * @param hierarchy - * @return - */ - protected List getLevels(Hierarchy hierarchy) { - if (levels == null) { - this.levels = new HashMap>(); - } - - List result = levels.get(hierarchy); - if (result == null) { - PlaceLevelsOnAxes transform = model - .getTransform(PlaceLevelsOnAxes.class); - - result = new ArrayList( - transform.findVisibleLevels(hierarchy)); - - Collections.sort(result, new Comparator() { - - @Override - public int compare(Level l1, Level l2) { - Integer d1 = l1.getDepth(); - Integer d2 = l2.getDepth(); - - return d1.compareTo(d2); - } - }); - - levels.put(hierarchy, result); - } - - return result; - } - - /** - * @param hierarchy - * @return - */ - protected List getMembers(Hierarchy hierarchy) { - if (members == null) { - this.members = new HashMap>(); - } - - List result = members.get(hierarchy); - if (result == null) { - PlaceMembersOnAxes transform = model - .getTransform(PlaceMembersOnAxes.class); - - result = transform.findVisibleMembers(hierarchy); - members.put(hierarchy, result); - } - - return result; - } - - /** - * @return the cubeNode - */ - public CubeNode getCubeNode() { - if (model != null && model.isInitialized()) { - if (cubeNode == null) { - this.cubeNode = new CubeNode(model.getCube()); - cubeNode.setNodeFilter(this); - } - } else { - this.cubeNode = null; - } - - return cubeNode; - } - - /** - * @param cubeNode - * the cubeNode to set - */ - public void setCubeNode(CubeNode cubeNode) { - this.cubeNode = cubeNode; - - this.dimensions = null; - this.hierarchies = null; - this.levels = null; - this.members = null; - } - - /** - * @return the cubeNode - */ - public TreeNode getTargetNode() { - if (model != null && model.isInitialized()) { - if (targetNode == null) { - this.targetNode = new DefaultTreeNode(); - - TreeNode columns = new DefaultTreeNode("columns", Axis.COLUMNS, - targetNode); - columns.setExpanded(true); - - configureAxis(columns, Axis.COLUMNS); - - TreeNode rows = new DefaultTreeNode("rows", Axis.ROWS, - targetNode); - rows.setExpanded(true); - - configureAxis(rows, Axis.ROWS); - } - } else { - this.targetNode = null; - } - - return targetNode; - } - - /** - * @param targetNode - * the targetNode to set - */ - public void setTargetNode(TreeNode targetNode) { - this.targetNode = targetNode; - } - - /** - * @param axisRoot - * @param axis - */ - protected void configureAxis(TreeNode axisRoot, Axis axis) { - List hierarchyList = getHierarchies(axis); - for (Hierarchy hierarchy : hierarchyList) { - TreeNode hierarchyNode = new DefaultTreeNode("hierarchy", - hierarchy, axisRoot); - hierarchyNode.setExpanded(true); - - Type type; - - try { - type = hierarchy.getDimension().getDimensionType(); - } catch (OlapException e) { - throw new FacesException(e); - } - - if (type == Type.MEASURE) { - List memberList = getMembers(hierarchy); - for (Member member : memberList) { - new DefaultTreeNode("measure", member, hierarchyNode); - } - } else { - List levelList = getLevels(hierarchy); - for (Level level : levelList) { - new DefaultTreeNode("level", level, hierarchyNode); - } - } - } - } - - /** - * @param id - * @return - */ - protected List getNodePath(String id) { - // there should be a cleaner way to get data from the dropped component. - // it's a limitation on PFs' side : - // http://code.google.com/p/primefaces/issues/detail?id=2781 - String[] segments = id.split(":"); - String[] indexSegments = segments[segments.length - 2].split("_"); - - List path = new ArrayList(indexSegments.length); - for (String index : indexSegments) { - path.add(Integer.parseInt(index)); - } - - return path; - } - - /** - * @param id - * @return - */ - protected boolean isSourceNode(String id) { - return id.startsWith("source-tree-form:cube-navigator"); - } - - /** - * @param e - */ - public void onDrop(DragDropEvent e) { - String dragId = e.getDragId(); - - if (StringUtils.isEmpty(dragId)) { - return; - } - - List path = getNodePath(dragId); - - boolean fromNavigator = isSourceNode(e.getDragId()); - if (fromNavigator) { - return; - } - - TreeNode node = findNodeFromPath(getTargetNode(), path); - - if (node.getData() instanceof Hierarchy) { - Axis axis = (Axis) node.getParent().getData(); - Hierarchy hierarchy = (Hierarchy) node.getData(); - - removeHierarhy(axis, hierarchy); - } else if (node.getData() instanceof Level) { - Axis axis = (Axis) node.getParent().getParent().getData(); - Level level = (Level) node.getData(); - - removeLevel(axis, level); - } else if (node.getData() instanceof Member) { - Member member = (Member) node.getData(); - - removeMember(member); - } - } - - /** - * @param e - */ - public void onDropOnAxis(DragDropEvent e) { - List sourcePath = getNodePath(e.getDragId()); - List targetPath = getNodePath(e.getDropId()); - - boolean fromNavigator = isSourceNode(e.getDragId()); - - TreeNode root = fromNavigator ? getCubeNode() : getTargetNode(); - - TreeNode source = findNodeFromPath(root, sourcePath); - TreeNode target = findNodeFromPath(getTargetNode(), targetPath); - - if (fromNavigator) { - onDropOnAxis(source, target); - } else if (source.getData() instanceof Hierarchy) { - Axis targetAxis = (Axis) target.getData(); - Hierarchy hierarchy = (Hierarchy) source.getData(); - - if (source.getParent().equals(target)) { - moveHierarhy(targetAxis, hierarchy, 0); - } else { - Axis sourceAxis = (Axis) source.getParent().getData(); - - removeHierarhy(sourceAxis, hierarchy); - addHierarhy(targetAxis, hierarchy); - } - } - } - - /** - * @param sourceNode - * @param targetNode - */ - protected void onDropOnAxis(TreeNode sourceNode, TreeNode targetNode) { - Axis axis = (Axis) targetNode.getData(); - - if (sourceNode instanceof HierarchyNode) { - HierarchyNode node = (HierarchyNode) sourceNode; - Hierarchy hierarchy = node.getObject(); - - addHierarhy(axis, hierarchy); - } else if (sourceNode instanceof LevelNode) { - LevelNode node = (LevelNode) sourceNode; - Level level = node.getObject(); - - addLevel(axis, level); - } else if (sourceNode instanceof MeasureNode) { - MeasureNode node = (MeasureNode) sourceNode; - Member member = node.getObject(); - - addMember(axis, member); - } - } - - /** - * @param e - */ - public void onDropOnHierarchy(DragDropEvent e) { - List sourcePath = getNodePath(e.getDragId()); - List targetPath = getNodePath(e.getDropId()); - - int position = targetPath.get(targetPath.size() - 1) + 1; - - boolean fromNavigator = isSourceNode(e.getDragId()); - - TreeNode root = fromNavigator ? getCubeNode() : getTargetNode(); - - TreeNode source = findNodeFromPath(root, sourcePath); - TreeNode target = findNodeFromPath(getTargetNode(), targetPath); - - if (fromNavigator) { - onDropOnHierarchy(source, target, position); - } else if (source.getData() instanceof Hierarchy) { - Axis targetAxis = (Axis) target.getParent().getData(); - Hierarchy hierarchy = (Hierarchy) source.getData(); - - if (source.getParent().equals(target.getParent())) { - moveHierarhy(targetAxis, hierarchy, position); - } else { - Axis sourceAxis = (Axis) source.getParent().getData(); - - removeHierarhy(sourceAxis, hierarchy); - addHierarhy(targetAxis, hierarchy, position); - } - } else if (source.getData() instanceof Member) { - if (source.getParent().equals(target)) { - moveMember((Member) source.getData(), 0); - } - } - } - - /** - * @param sourceNode - * @param targetNode - * @param position - */ - protected void onDropOnHierarchy(TreeNode sourceNode, TreeNode targetNode, - int position) { - Axis axis = (Axis) targetNode.getParent().getData(); - - if (sourceNode instanceof HierarchyNode) { - HierarchyNode node = (HierarchyNode) sourceNode; - Hierarchy hierarchy = node.getObject(); - - addHierarhy(axis, hierarchy, position); - } else if (sourceNode instanceof LevelNode) { - LevelNode node = (LevelNode) sourceNode; - Level level = node.getObject(); - - addLevel(axis, level, position); - } else if (sourceNode instanceof MeasureNode) { - MeasureNode node = (MeasureNode) sourceNode; - Member member = node.getObject(); - - if (member.getHierarchy().equals(targetNode.getData())) { - addMember(axis, member); - } else { - addMember(axis, member, position); - } - } - } - - /** - * @param e - */ - public void onDropOnMember(DragDropEvent e) { - List sourcePath = getNodePath(e.getDragId()); - List targetPath = getNodePath(e.getDropId()); - - int position = targetPath.get(targetPath.size() - 1) + 1; - - boolean fromNavigator = isSourceNode(e.getDragId()); - - TreeNode root = fromNavigator ? getCubeNode() : getTargetNode(); - - TreeNode source = findNodeFromPath(root, sourcePath); - TreeNode target = findNodeFromPath(getTargetNode(), targetPath); - - Member member; - - if (fromNavigator) { - if (!(source instanceof MeasureNode)) { - return; - } - - member = ((MeasureNode) source).getObject(); - - Axis axis = (Axis) target.getParent().getParent().getData(); - addMember(axis, member, position); - } else { - if (!(source.getData() instanceof Member)) { - return; - } - - member = (Member) source.getData(); - moveMember(member, position); - } - } - - /** - * @param axis - * @param hierarchy - */ - protected void addHierarhy(Axis axis, Hierarchy hierarchy) { - addHierarhy(axis, hierarchy, 0); - } - - /** - * @param axis - * @param hierarchy - * @param position - */ - protected void addHierarhy(Axis axis, Hierarchy hierarchy, int position) { - for (Axis ax : new Axis[] { Axis.COLUMNS, Axis.ROWS, Axis.FILTER }) { - List hiersInAxis = getHierarchies(ax); - - if (hiersInAxis.contains(hierarchy)) { - FacesContext context = FacesContext.getCurrentInstance(); - - ResourceBundle bundle = context.getApplication() - .getResourceBundle(context, "msg"); - - String title = bundle.getString("warn.hierarchy.exists.title"); - String message = String.format( - bundle.getString("warn.hierarchy.exists.message"), - ax.name()); - - context.addMessage(null, new FacesMessage( - FacesMessage.SEVERITY_WARN, title, message)); - return; - } - } - - PlaceHierarchiesOnAxes transform = getModel().getTransform( - PlaceHierarchiesOnAxes.class); - - transform.addHierarchy(axis, hierarchy, false, position); - } - - /** - * @param axis - * @param hierarchy - * @param position - */ - protected void moveHierarhy(Axis axis, Hierarchy hierarchy, int position) { - PlaceHierarchiesOnAxes transform = getModel().getTransform( - PlaceHierarchiesOnAxes.class); - transform.moveHierarchy(axis, hierarchy, position); - } - - /** - * @param axis - * @param hierarchy - */ - protected void removeHierarhy(Axis axis, Hierarchy hierarchy) { - PlaceHierarchiesOnAxes transform = getModel().getTransform( - PlaceHierarchiesOnAxes.class); - transform.removeHierarchy(axis, hierarchy); - } - - /** - * @param axis - * @param level - */ - protected void addLevel(Axis axis, Level level) { - addLevel(axis, level, 0); - } - - /** - * @param axis - * @param level - * @param position - */ - protected void addLevel(Axis axis, Level level, int position) { - Hierarchy hierarchy = level.getHierarchy(); - - for (Axis ax : new Axis[] { Axis.COLUMNS, Axis.ROWS, Axis.FILTER }) { - if (ax.equals(axis)) { - continue; - } - - List hiersInAxis = getHierarchies(ax); - - if (hiersInAxis.contains(hierarchy)) { - FacesContext context = FacesContext.getCurrentInstance(); - - ResourceBundle bundle = context.getApplication() - .getResourceBundle(context, "msg"); - - String title = bundle.getString("warn.level.exists.title"); - String message = String.format( - bundle.getString("warn.level.exists.message"), - ax.name()); - - context.addMessage(null, new FacesMessage( - FacesMessage.SEVERITY_WARN, title, message)); - return; - } - } - - PlaceLevelsOnAxes transform = getModel().getTransform( - PlaceLevelsOnAxes.class); - transform.addLevel(axis, level, position); - } - - /** - * @param axis - * @param level - */ - protected void removeLevel(Axis axis, Level level) { - PlaceLevelsOnAxes transform = getModel().getTransform( - PlaceLevelsOnAxes.class); - transform.removeLevel(axis, level); - } - - /** - * @param member - * @param position - */ - protected void addMember(Member member, int position) { - PlaceMembersOnAxes transform = model - .getTransform(PlaceMembersOnAxes.class); - - transform.addMember(member, position); - } - - /** - * @param axis - * @param member - */ - protected void addMember(Axis axis, Member member) { - addMember(axis, member, 0); - } - - /** - * @param axis - * @param member - * @param position - */ - protected void addMember(Axis axis, Member member, int position) { - Hierarchy hierarchy = member.getHierarchy(); - - for (Axis ax : new Axis[] { Axis.COLUMNS, Axis.ROWS, Axis.FILTER }) { - if (ax.equals(axis)) { - continue; - } - - List hiersInAxis = getHierarchies(ax); - - if (hiersInAxis.contains(hierarchy)) { - FacesContext context = FacesContext.getCurrentInstance(); - - ResourceBundle bundle = context.getApplication() - .getResourceBundle(context, "msg"); - - String title = bundle.getString("warn.member.exists.title"); - String message = String.format( - bundle.getString("warn.member.exists.message"), - ax.name()); - - context.addMessage(null, new FacesMessage( - FacesMessage.SEVERITY_WARN, title, message)); - return; - } - } - - PlaceMembersOnAxes transform = getModel().getTransform( - PlaceMembersOnAxes.class); - transform.addMember(axis, member, position); - } - - /** - * @param member - * @param position - */ - protected void moveMember(Member member, int position) { - PlaceMembersOnAxes transform = model - .getTransform(PlaceMembersOnAxes.class); - - transform.moveMember(member, position); - } - - /** - * @param member - */ - protected void removeMember(Member member) { - PlaceMembersOnAxes transform = getModel().getTransform( - PlaceMembersOnAxes.class); - transform.removeMember(member); - } - - /** - * @param parent - * @param indexes - * @return - */ - protected TreeNode findNodeFromPath(TreeNode parent, List indexes) { - if (indexes.size() > 1) { - return findNodeFromPath(parent.getChildren().get(indexes.get(0)), - indexes.subList(1, indexes.size())); - } else { - return parent.getChildren().get(indexes.get(0)); - } - } - - /** - * @see org.pivot4j.ModelChangeListener#modelInitialized(org.pivot4j.ModelChangeEvent) - */ - @Override - public void modelInitialized(ModelChangeEvent e) { - } - - /** - * @see org.pivot4j.ModelChangeListener#modelDestroyed(org.pivot4j.ModelChangeEvent) - */ - @Override - public void modelDestroyed(ModelChangeEvent e) { - } - - /** - * @see org.pivot4j.ModelChangeListener#modelChanged(org.pivot4j.ModelChangeEvent) - */ - @Override - public void modelChanged(ModelChangeEvent e) { - } - - /** - * @see org.pivot4j.ModelChangeListener#structureChanged(org.pivot4j.ModelChangeEvent) - */ - @Override - public void structureChanged(ModelChangeEvent e) { - this.cubeNode = null; - this.targetNode = null; - - this.dimensions = null; - this.hierarchies = null; - this.levels = null; - this.members = null; - } - - /** - * @see org.pivot4j.analytics.component.tree.NodeFilter#isSelected(org.olap4j.metadata.MetadataElement) - */ - @Override - public boolean isSelected(T element) { - if (element instanceof Dimension) { - Dimension dimension = (Dimension) element; - return getDimensions(Axis.COLUMNS).contains(dimension) - || getDimensions(Axis.ROWS).contains(dimension); - } - - if (element instanceof Hierarchy) { - Hierarchy hierarchy = (Hierarchy) element; - return getHierarchies(Axis.COLUMNS).contains(hierarchy) - || getHierarchies(Axis.ROWS).contains(hierarchy); - } - - if (element instanceof Level) { - Level level = (Level) element; - return getLevels(level.getHierarchy()).contains(level); - } - - if (element instanceof Member) { - Member member = (Member) element; - return getMembers(member.getHierarchy()).contains(member); - } - - return false; - } - - /** - * @see org.pivot4j.analytics.component.tree.NodeFilter#isSelectable(org.olap4j.metadata.MetadataElement) - */ - @Override - public boolean isSelectable(T element) { - return false; - } - - /** - * @see org.pivot4j.analytics.component.tree.NodeFilter#isActive(org.olap4j.metadata.MetadataElement) - */ - @Override - public boolean isActive(T element) { - return false; - } - - /** - * @see org.pivot4j.analytics.component.tree.NodeFilter#isVisible(org.olap4j.metadata.MetadataElement) - */ - @Override - public boolean isVisible(T element) { - if (element instanceof Member) { - return !isSelected(element); - } - - if (element instanceof Hierarchy) { - return !getHierarchies(Axis.FILTER).contains(element); - } - - return true; - } - - /** - * @see org.pivot4j.analytics.component.tree.NodeFilter#isExpanded(org.olap4j.metadata.MetadataElement) - */ - @Override - public boolean isExpanded(T element) { - if (element instanceof Dimension) { - return true; - } else if (element instanceof Hierarchy) { - Hierarchy hierarchy = (Hierarchy) element; - - boolean isMeasure; - - try { - isMeasure = hierarchy.getDimension().getDimensionType() == Type.MEASURE; - } catch (OlapException e) { - throw new FacesException(e); - } - - return isMeasure || isSelected(element); - } - - return false; - } + @ManagedProperty(value = "#{pivotStateManager.model}") + private PivotModel model; + + private CubeNode cubeNode; + + private TreeNode targetNode; + + private List dimensions; + + private Map> hierarchies; + + private Map> levels; + + private Map> members; + + @PostConstruct + protected void initialize() { + if (model != null) { + model.addModelChangeListener(this); + } + } + + @PreDestroy + protected void destroy() { + if (model != null) { + model.removeModelChangeListener(this); + } + } + + /** + * @return the model + */ + public PivotModel getModel() { + return model; + } + + /** + * @param model the model to set + */ + public void setModel(PivotModel model) { + this.model = model; + } + + /** + * @param axis + * @return + */ + protected List getDimensions(Axis axis) { + if (dimensions == null) { + this.dimensions = new ArrayList(); + + for (Hierarchy hierarchy : getHierarchies(axis)) { + dimensions.add(hierarchy.getDimension()); + } + } + + return dimensions; + } + + /** + * @param axis + * @return + */ + protected List getHierarchies(Axis axis) { + if (hierarchies == null) { + this.hierarchies = new HashMap>(2); + } + + List result = hierarchies.get(axis); + if (result == null) { + if (axis.equals(Axis.FILTER)) { + ChangeSlicer transform = model.getTransform(ChangeSlicer.class); + result = transform.getHierarchies(); + } else { + PlaceHierarchiesOnAxes transform = model + .getTransform(PlaceHierarchiesOnAxes.class); + result = transform.findVisibleHierarchies(axis); + } + + hierarchies.put(axis, result); + } + + return result; + } + + /** + * @param hierarchy + * @return + */ + protected List getLevels(Hierarchy hierarchy) { + if (levels == null) { + this.levels = new HashMap>(); + } + + List result = levels.get(hierarchy); + if (result == null) { + PlaceLevelsOnAxes transform = model + .getTransform(PlaceLevelsOnAxes.class); + + result = new ArrayList( + transform.findVisibleLevels(hierarchy)); + + Collections.sort(result, new Comparator() { + + @Override + public int compare(Level l1, Level l2) { + Integer d1 = l1.getDepth(); + Integer d2 = l2.getDepth(); + + return d1.compareTo(d2); + } + }); + + levels.put(hierarchy, result); + } + + return result; + } + + /** + * @param hierarchy + * @return + */ + protected List getMembers(Hierarchy hierarchy) { + if (members == null) { + this.members = new HashMap>(); + } + + List result = members.get(hierarchy); + if (result == null) { + PlaceMembersOnAxes transform = model + .getTransform(PlaceMembersOnAxes.class); + + result = transform.findVisibleMembers(hierarchy); + members.put(hierarchy, result); + } + + return result; + } + + /** + * @return the cubeNode + */ + public CubeNode getCubeNode() { + if (model != null && model.isInitialized()) { + if (cubeNode == null) { + this.cubeNode = new CubeNode(model.getCube()); + cubeNode.setNodeFilter(this); + } + } else { + this.cubeNode = null; + } + + return cubeNode; + } + + /** + * @param cubeNode the cubeNode to set + */ + public void setCubeNode(CubeNode cubeNode) { + this.cubeNode = cubeNode; + + this.dimensions = null; + this.hierarchies = null; + this.levels = null; + this.members = null; + } + + /** + * @return the cubeNode + */ + public TreeNode getTargetNode() { + if (model != null && model.isInitialized()) { + if (targetNode == null) { + this.targetNode = new DefaultTreeNode(); + + TreeNode columns = new DefaultTreeNode("columns", Axis.COLUMNS, + targetNode); + columns.setExpanded(true); + + configureAxis(columns, Axis.COLUMNS); + + TreeNode rows = new DefaultTreeNode("rows", Axis.ROWS, + targetNode); + rows.setExpanded(true); + + configureAxis(rows, Axis.ROWS); + } + } else { + this.targetNode = null; + } + + return targetNode; + } + + /** + * @param targetNode the targetNode to set + */ + public void setTargetNode(TreeNode targetNode) { + this.targetNode = targetNode; + } + + /** + * @param axisRoot + * @param axis + */ + protected void configureAxis(TreeNode axisRoot, Axis axis) { + List hierarchyList = getHierarchies(axis); + for (Hierarchy hierarchy : hierarchyList) { + TreeNode hierarchyNode = new DefaultTreeNode("hierarchy", + hierarchy, axisRoot); + hierarchyNode.setExpanded(true); + + Type type; + + try { + type = hierarchy.getDimension().getDimensionType(); + } catch (OlapException e) { + throw new FacesException(e); + } + + if (type == Type.MEASURE) { + List memberList = getMembers(hierarchy); + for (Member member : memberList) { + new DefaultTreeNode("measure", member, hierarchyNode); + } + } else { + List levelList = getLevels(hierarchy); + for (Level level : levelList) { + new DefaultTreeNode("level", level, hierarchyNode); + } + } + } + } + + /** + * @param id + * @return + */ + protected List getNodePath(String id) { + // there should be a cleaner way to get data from the dropped component. + // it's a limitation on PFs' side : + // http://code.google.com/p/primefaces/issues/detail?id=2781 + String[] segments = id.split(":"); + String[] indexSegments = segments[segments.length - 2].split("_"); + + List path = new ArrayList(indexSegments.length); + for (String index : indexSegments) { + path.add(Integer.parseInt(index)); + } + + return path; + } + + /** + * @param id + * @return + */ + protected boolean isSourceNode(String id) { + return id.startsWith("source-tree-form:cube-navigator"); + } + + /** + * @param e + */ + public void onDrop(DragDropEvent e) { + String dragId = e.getDragId(); + + if (StringUtils.isEmpty(dragId)) { + return; + } + + List path = getNodePath(dragId); + + boolean fromNavigator = isSourceNode(e.getDragId()); + if (fromNavigator) { + return; + } + + TreeNode node = findNodeFromPath(getTargetNode(), path); + + if (node.getData() instanceof Hierarchy) { + Axis axis = (Axis) node.getParent().getData(); + Hierarchy hierarchy = (Hierarchy) node.getData(); + + removeHierarhy(axis, hierarchy); + } else if (node.getData() instanceof Level) { + Axis axis = (Axis) node.getParent().getParent().getData(); + Level level = (Level) node.getData(); + + removeLevel(axis, level); + } else if (node.getData() instanceof Member) { + Member member = (Member) node.getData(); + + removeMember(member); + } + } + + /** + * @param e + */ + public void onDropOnAxis(DragDropEvent e) { + List sourcePath = getNodePath(e.getDragId()); + List targetPath = getNodePath(e.getDropId()); + + boolean fromNavigator = isSourceNode(e.getDragId()); + + TreeNode root = fromNavigator ? getCubeNode() : getTargetNode(); + + TreeNode source = findNodeFromPath(root, sourcePath); + TreeNode target = findNodeFromPath(getTargetNode(), targetPath); + + if (fromNavigator) { + onDropOnAxis(source, target); + } else if (source.getData() instanceof Hierarchy) { + Axis targetAxis = (Axis) target.getData(); + Hierarchy hierarchy = (Hierarchy) source.getData(); + + if (source.getParent().equals(target)) { + moveHierarhy(targetAxis, hierarchy, 0); + } else { + Axis sourceAxis = (Axis) source.getParent().getData(); + + removeHierarhy(sourceAxis, hierarchy); + addHierarhy(targetAxis, hierarchy); + } + } + } + + /** + * @param sourceNode + * @param targetNode + */ + protected void onDropOnAxis(TreeNode sourceNode, TreeNode targetNode) { + Axis axis = (Axis) targetNode.getData(); + + if (sourceNode instanceof HierarchyNode) { + HierarchyNode node = (HierarchyNode) sourceNode; + Hierarchy hierarchy = node.getObject(); + + addHierarhy(axis, hierarchy); + } else if (sourceNode instanceof LevelNode) { + LevelNode node = (LevelNode) sourceNode; + Level level = node.getObject(); + + addLevel(axis, level); + } else if (sourceNode instanceof MeasureNode) { + MeasureNode node = (MeasureNode) sourceNode; + Member member = node.getObject(); + + addMember(axis, member); + } + } + + /** + * @param e + */ + public void onDropOnHierarchy(DragDropEvent e) { + List sourcePath = getNodePath(e.getDragId()); + List targetPath = getNodePath(e.getDropId()); + + int position = targetPath.get(targetPath.size() - 1) + 1; + + boolean fromNavigator = isSourceNode(e.getDragId()); + + TreeNode root = fromNavigator ? getCubeNode() : getTargetNode(); + + TreeNode source = findNodeFromPath(root, sourcePath); + TreeNode target = findNodeFromPath(getTargetNode(), targetPath); + + if (fromNavigator) { + onDropOnHierarchy(source, target, position); + } else if (source.getData() instanceof Hierarchy) { + Axis targetAxis = (Axis) target.getParent().getData(); + Hierarchy hierarchy = (Hierarchy) source.getData(); + + if (source.getParent().equals(target.getParent())) { + moveHierarhy(targetAxis, hierarchy, position); + } else { + Axis sourceAxis = (Axis) source.getParent().getData(); + + removeHierarhy(sourceAxis, hierarchy); + addHierarhy(targetAxis, hierarchy, position); + } + } else if (source.getData() instanceof Member) { + if (source.getParent().equals(target)) { + moveMember((Member) source.getData(), 0); + } + } + } + + /** + * @param sourceNode + * @param targetNode + * @param position + */ + protected void onDropOnHierarchy(TreeNode sourceNode, TreeNode targetNode, + int position) { + Axis axis = (Axis) targetNode.getParent().getData(); + + if (sourceNode instanceof HierarchyNode) { + HierarchyNode node = (HierarchyNode) sourceNode; + Hierarchy hierarchy = node.getObject(); + + addHierarhy(axis, hierarchy, position); + } else if (sourceNode instanceof LevelNode) { + LevelNode node = (LevelNode) sourceNode; + Level level = node.getObject(); + + addLevel(axis, level, position); + } else if (sourceNode instanceof MeasureNode) { + MeasureNode node = (MeasureNode) sourceNode; + Member member = node.getObject(); + + if (member.getHierarchy().equals(targetNode.getData())) { + addMember(axis, member); + } else { + addMember(axis, member, position); + } + } + } + + /** + * @param e + */ + public void onDropOnMember(DragDropEvent e) { + List sourcePath = getNodePath(e.getDragId()); + List targetPath = getNodePath(e.getDropId()); + + int position = targetPath.get(targetPath.size() - 1) + 1; + + boolean fromNavigator = isSourceNode(e.getDragId()); + + TreeNode root = fromNavigator ? getCubeNode() : getTargetNode(); + + TreeNode source = findNodeFromPath(root, sourcePath); + TreeNode target = findNodeFromPath(getTargetNode(), targetPath); + + Member member; + + if (fromNavigator) { + if (!(source instanceof MeasureNode)) { + return; + } + + member = ((MeasureNode) source).getObject(); + + Axis axis = (Axis) target.getParent().getParent().getData(); + addMember(axis, member, position); + } else { + if (!(source.getData() instanceof Member)) { + return; + } + + member = (Member) source.getData(); + moveMember(member, position); + } + } + + /** + * @param axis + * @param hierarchy + */ + protected void addHierarhy(Axis axis, Hierarchy hierarchy) { + addHierarhy(axis, hierarchy, 0); + } + + /** + * @param axis + * @param hierarchy + * @param position + */ + protected void addHierarhy(Axis axis, Hierarchy hierarchy, int position) { + for (Axis ax : new Axis[]{Axis.COLUMNS, Axis.ROWS, Axis.FILTER}) { + List hiersInAxis = getHierarchies(ax); + + if (hiersInAxis.contains(hierarchy)) { + FacesContext context = FacesContext.getCurrentInstance(); + + ResourceBundle bundle = context.getApplication() + .getResourceBundle(context, "msg"); + + String title = bundle.getString("warn.hierarchy.exists.title"); + String message = String.format( + bundle.getString("warn.hierarchy.exists.message"), + ax.name()); + + context.addMessage(null, new FacesMessage( + FacesMessage.SEVERITY_WARN, title, message)); + return; + } + } + + PlaceHierarchiesOnAxes transform = getModel().getTransform( + PlaceHierarchiesOnAxes.class); + + transform.addHierarchy(axis, hierarchy, false, position); + } + + /** + * @param axis + * @param hierarchy + * @param position + */ + protected void moveHierarhy(Axis axis, Hierarchy hierarchy, int position) { + PlaceHierarchiesOnAxes transform = getModel().getTransform( + PlaceHierarchiesOnAxes.class); + transform.moveHierarchy(axis, hierarchy, position); + } + + /** + * @param axis + * @param hierarchy + */ + protected void removeHierarhy(Axis axis, Hierarchy hierarchy) { + PlaceHierarchiesOnAxes transform = getModel().getTransform( + PlaceHierarchiesOnAxes.class); + transform.removeHierarchy(axis, hierarchy); + } + + /** + * @param axis + * @param level + */ + protected void addLevel(Axis axis, Level level) { + addLevel(axis, level, 0); + } + + /** + * @param axis + * @param level + * @param position + */ + protected void addLevel(Axis axis, Level level, int position) { + Hierarchy hierarchy = level.getHierarchy(); + + for (Axis ax : new Axis[]{Axis.COLUMNS, Axis.ROWS, Axis.FILTER}) { + if (ax.equals(axis)) { + continue; + } + + List hiersInAxis = getHierarchies(ax); + + if (hiersInAxis.contains(hierarchy)) { + FacesContext context = FacesContext.getCurrentInstance(); + + ResourceBundle bundle = context.getApplication() + .getResourceBundle(context, "msg"); + + String title = bundle.getString("warn.level.exists.title"); + String message = String.format( + bundle.getString("warn.level.exists.message"), + ax.name()); + + context.addMessage(null, new FacesMessage( + FacesMessage.SEVERITY_WARN, title, message)); + return; + } + } + + PlaceLevelsOnAxes transform = getModel().getTransform( + PlaceLevelsOnAxes.class); + transform.addLevel(axis, level, position); + } + + /** + * @param axis + * @param level + */ + protected void removeLevel(Axis axis, Level level) { + PlaceLevelsOnAxes transform = getModel().getTransform( + PlaceLevelsOnAxes.class); + transform.removeLevel(axis, level); + } + + /** + * @param member + * @param position + */ + protected void addMember(Member member, int position) { + PlaceMembersOnAxes transform = model + .getTransform(PlaceMembersOnAxes.class); + + transform.addMember(member, position); + } + + /** + * @param axis + * @param member + */ + protected void addMember(Axis axis, Member member) { + addMember(axis, member, 0); + } + + /** + * @param axis + * @param member + * @param position + */ + protected void addMember(Axis axis, Member member, int position) { + Hierarchy hierarchy = member.getHierarchy(); + + for (Axis ax : new Axis[]{Axis.COLUMNS, Axis.ROWS, Axis.FILTER}) { + if (ax.equals(axis)) { + continue; + } + + List hiersInAxis = getHierarchies(ax); + + if (hiersInAxis.contains(hierarchy)) { + FacesContext context = FacesContext.getCurrentInstance(); + + ResourceBundle bundle = context.getApplication() + .getResourceBundle(context, "msg"); + + String title = bundle.getString("warn.member.exists.title"); + String message = String.format( + bundle.getString("warn.member.exists.message"), + ax.name()); + + context.addMessage(null, new FacesMessage( + FacesMessage.SEVERITY_WARN, title, message)); + return; + } + } + + PlaceMembersOnAxes transform = getModel().getTransform( + PlaceMembersOnAxes.class); + transform.addMember(axis, member, position); + } + + /** + * @param member + * @param position + */ + protected void moveMember(Member member, int position) { + PlaceMembersOnAxes transform = model + .getTransform(PlaceMembersOnAxes.class); + + transform.moveMember(member, position); + } + + /** + * @param member + */ + protected void removeMember(Member member) { + PlaceMembersOnAxes transform = getModel().getTransform( + PlaceMembersOnAxes.class); + transform.removeMember(member); + } + + /** + * @param parent + * @param indexes + * @return + */ + protected TreeNode findNodeFromPath(TreeNode parent, List indexes) { + if (indexes.size() > 1) { + return findNodeFromPath(parent.getChildren().get(indexes.get(0)), + indexes.subList(1, indexes.size())); + } else { + return parent.getChildren().get(indexes.get(0)); + } + } + + /** + * @see + * org.pivot4j.ModelChangeListener#modelInitialized(org.pivot4j.ModelChangeEvent) + */ + @Override + public void modelInitialized(ModelChangeEvent e) { + } + + /** + * @see + * org.pivot4j.ModelChangeListener#modelDestroyed(org.pivot4j.ModelChangeEvent) + */ + @Override + public void modelDestroyed(ModelChangeEvent e) { + } + + /** + * @see + * org.pivot4j.ModelChangeListener#modelChanged(org.pivot4j.ModelChangeEvent) + */ + @Override + public void modelChanged(ModelChangeEvent e) { + } + + /** + * @see + * org.pivot4j.ModelChangeListener#structureChanged(org.pivot4j.ModelChangeEvent) + */ + @Override + public void structureChanged(ModelChangeEvent e) { + this.cubeNode = null; + this.targetNode = null; + + this.dimensions = null; + this.hierarchies = null; + this.levels = null; + this.members = null; + } + + /** + * @see + * org.pivot4j.analytics.component.tree.NodeFilter#isSelected(org.olap4j.metadata.MetadataElement) + */ + @Override + public boolean isSelected(T element) { + if (element instanceof Dimension) { + Dimension dimension = (Dimension) element; + return getDimensions(Axis.COLUMNS).contains(dimension) + || getDimensions(Axis.ROWS).contains(dimension); + } + + if (element instanceof Hierarchy) { + Hierarchy hierarchy = (Hierarchy) element; + return getHierarchies(Axis.COLUMNS).contains(hierarchy) + || getHierarchies(Axis.ROWS).contains(hierarchy); + } + + if (element instanceof Level) { + Level level = (Level) element; + return getLevels(level.getHierarchy()).contains(level); + } + + if (element instanceof Member) { + Member member = (Member) element; + return getMembers(member.getHierarchy()).contains(member); + } + + return false; + } + + /** + * @see + * org.pivot4j.analytics.component.tree.NodeFilter#isSelectable(org.olap4j.metadata.MetadataElement) + */ + @Override + public boolean isSelectable(T element) { + return false; + } + + /** + * @see + * org.pivot4j.analytics.component.tree.NodeFilter#isActive(org.olap4j.metadata.MetadataElement) + */ + @Override + public boolean isActive(T element) { + return false; + } + + /** + * @see + * org.pivot4j.analytics.component.tree.NodeFilter#isVisible(org.olap4j.metadata.MetadataElement) + */ + @Override + public boolean isVisible(T element) { + if (element instanceof Member) { + return !isSelected(element); + } + + if (element instanceof Hierarchy) { + return !getHierarchies(Axis.FILTER).contains(element); + } + + return true; + } + + /** + * @see + * org.pivot4j.analytics.component.tree.NodeFilter#isExpanded(org.olap4j.metadata.MetadataElement) + */ + @Override + public boolean isExpanded(T element) { + if (element instanceof Dimension) { + return true; + } else if (element instanceof Hierarchy) { + Hierarchy hierarchy = (Hierarchy) element; + + boolean isMeasure; + + try { + isMeasure = hierarchy.getDimension().getDimensionType() == Type.MEASURE; + } catch (OlapException e) { + throw new FacesException(e); + } + + return isMeasure || isSelected(element); + } + + return false; + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/PivotComponentBuilder.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/PivotComponentBuilder.java index 0e404638..dafdf067 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/PivotComponentBuilder.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/PivotComponentBuilder.java @@ -13,6 +13,7 @@ import java.util.List; import java.util.Map; import java.util.ResourceBundle; +import java.util.UUID; import javax.el.ExpressionFactory; import javax.el.MethodExpression; @@ -52,46 +53,49 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.fasterxml.uuid.Generators; +import java.util.StringTokenizer; + public class PivotComponentBuilder extends AbstractRenderCallback implements TableRenderCallback { - + private Logger logger = LoggerFactory.getLogger(getClass()); - + private Map iconMap; - + private UIComponent gridPanel; - + private UIComponent filterPanel; - + private FacesContext facesContext; - + private ExpressionFactory expressionFactory; - + private PanelGrid grid; - + private HtmlPanelGroup header; - + private Row row; - + private Column column; - + private int commandIndex = 0; - + private boolean scenarioEnabled = false; - + private String updateTarget; - + private static Map styleClassResolvers; - + static { styleClassResolvers = new HashMap(); - + styleClassResolvers.put(VALUE, new ValueStyleClassResolver()); styleClassResolvers.put(AGG_VALUE, new AggregationStyleClassResolver()); - + StyleClassResolver titleStlyeResolver = new TitleStyleClassResolver(); - + styleClassResolvers.put(LABEL, titleStlyeResolver); styleClassResolvers.put(TITLE, titleStlyeResolver); styleClassResolvers.put(FILL, titleStlyeResolver); @@ -102,17 +106,17 @@ public class PivotComponentBuilder extends */ public PivotComponentBuilder(FacesContext facesContext) { this.facesContext = facesContext; - + if (facesContext != null) { Application application = facesContext.getApplication(); - + this.expressionFactory = application.getExpressionFactory(); } // Map command mode names to jQuery's predefined icon names. It can be // also done by CSS. this.iconMap = new HashMap(); - + iconMap.put("expandPosition-position", "ui-icon-plus"); iconMap.put("collapsePosition-position", "ui-icon-minus"); iconMap.put("expandMember-member", "ui-icon-plusthick"); @@ -178,57 +182,59 @@ protected Logger getLogger() { } /** - * @see org.pivot4j.ui.AbstractRenderCallback#startRender(org.pivot4j.ui.RenderContext) + * @see + * org.pivot4j.ui.AbstractRenderCallback#startRender(org.pivot4j.ui.RenderContext) */ @Override public void startRender(TableRenderContext context) { super.startRender(context); - + ResourceBundle resources = facesContext.getApplication() .getResourceBundle(facesContext, "msg"); context.setResourceBundle(resources); - + getRenderPropertyUtils().setSuppressErrors(true); - + this.commandIndex = 0; this.scenarioEnabled = context.getModel().isScenarioSupported() && context.getModel().getScenario() != null; - + gridPanel.getFacets().clear(); gridPanel.getChildren().clear(); - + filterPanel.getFacets().clear(); filterPanel.getChildren().clear(); - + List targets = new LinkedList(); - + targets.add(":grid-form"); - + UIViewRoot viewRoot = FacesContext.getCurrentInstance().getViewRoot(); - + if (viewRoot.findComponent("editor-form") != null) { targets.add(":editor-form:mdx-editor"); targets.add(":editor-form:editor-toolbar"); } - + if (viewRoot.findComponent("source-tree-form") != null) { targets.add(":source-tree-form"); } - + if (viewRoot.findComponent("target-tree-form") != null) { targets.add(":target-tree-form"); } - + this.updateTarget = StringUtils.join(targets, ","); } /** - * @see org.pivot4j.ui.table.TableRenderCallback#startTable(org.pivot4j.ui.table.TableRenderContext) + * @see + * org.pivot4j.ui.table.TableRenderCallback#startTable(org.pivot4j.ui.table.TableRenderContext) */ @Override public void startTable(TableRenderContext context) { this.grid = new PanelGrid(); - + if (context.getAxis() == Axis.FILTER) { grid.setStyleClass("filter-grid"); } else { @@ -237,7 +243,8 @@ public void startTable(TableRenderContext context) { } /** - * @see org.pivot4j.ui.table.TableRenderCallback#startHeader(org.pivot4j.ui.table.TableRenderContext) + * @see + * org.pivot4j.ui.table.TableRenderCallback#startHeader(org.pivot4j.ui.table.TableRenderContext) */ @Override public void startHeader(TableRenderContext context) { @@ -245,26 +252,29 @@ public void startHeader(TableRenderContext context) { } /** - * @see org.pivot4j.ui.table.TableRenderCallback#endHeader(org.pivot4j.ui.table.TableRenderContext) + * @see + * org.pivot4j.ui.table.TableRenderCallback#endHeader(org.pivot4j.ui.table.TableRenderContext) */ @Override public void endHeader(TableRenderContext context) { if (header.getChildCount() > 0) { grid.getFacets().put("header", header); } - + this.header = null; } /** - * @see org.pivot4j.ui.table.TableRenderCallback#startBody(org.pivot4j.ui.table.TableRenderContext) + * @see + * org.pivot4j.ui.table.TableRenderCallback#startBody(org.pivot4j.ui.table.TableRenderContext) */ @Override public void startBody(TableRenderContext context) { } /** - * @see org.pivot4j.ui.table.TableRenderCallback#startRow(org.pivot4j.ui.table.TableRenderContext) + * @see + * org.pivot4j.ui.table.TableRenderCallback#startRow(org.pivot4j.ui.table.TableRenderContext) */ @Override public void startRow(TableRenderContext context) { @@ -272,90 +282,94 @@ public void startRow(TableRenderContext context) { } /** - * @see org.pivot4j.ui.table.TableRenderCallback#startCell(org.pivot4j.ui.table.TableRenderContext) + * @see + * org.pivot4j.ui.table.TableRenderCallback#startCell(org.pivot4j.ui.table.TableRenderContext) */ @Override public void startCell(TableRenderContext context) { this.column = new Column(); - - String id = "col-" + column.hashCode(); - + + UUID uuid = Generators.timeBasedGenerator().generate(); + + String id = "col-" + uuid.toString(); + column.setId(id); column.setColspan(context.getColumnSpan()); column.setRowspan(context.getRowSpan()); - + column.setFilterable(true); + RenderPropertyUtils propertyUtils = getRenderPropertyUtils(); - + String propertyCategory = context.getRenderPropertyCategory(); - + StringWriter writer = new StringWriter(); CssWriter cssWriter = new CssWriter(writer); - + String type = context.getCellType(); - + if (type.equals(LABEL) && !context.getRenderer().getShowParentMembers() && context.getMember() != null && context.getAxis() != Axis.FILTER) { int padding = context.getMember().getDepth() * 10; cssWriter.writeStyle("padding-left", padding + "px"); } - + String fgColor = propertyUtils.getString("fgColor", propertyCategory, null); - + if (fgColor != null) { cssWriter.writeStyle("color", fgColor); } - + String bgColor = propertyUtils.getString("bgColor", propertyCategory, null); - + if (bgColor != null) { cssWriter.writeStyle("background-color", bgColor); cssWriter.writeStyle("background-image", "none"); } - + String fontFamily = propertyUtils.getString("fontFamily", propertyCategory, null); - + if (fontFamily != null) { cssWriter.writeStyle("font-family", fontFamily); } - + String fontSize = propertyUtils.getString("fontSize", propertyCategory, null); - + if (fontSize != null) { cssWriter.writeStyle("font-size", fontSize); } - + String fontStyle = propertyUtils.getString("fontStyle", propertyCategory, null); - + if (fontStyle != null) { if (fontStyle.contains("bold")) { cssWriter.writeStyle("font-weight", "bold"); } - + if (fontStyle.contains("italic")) { cssWriter.writeStyle("font-style", "oblique"); } } - + writer.flush(); - + IOUtils.closeQuietly(writer); - + String style = writer.toString(); - + if (StringUtils.isNotEmpty(style)) { column.setStyle(style); } - + String styleClass = getStyleClass(context); String styleClassProperty = propertyUtils.getString("styleClass", propertyCategory, null); - + if (styleClassProperty != null) { if (styleClass == null) { styleClass = styleClassProperty; @@ -363,7 +377,7 @@ public void startCell(TableRenderContext context) { styleClass += " " + styleClassProperty; } } - + column.setStyleClass(styleClass); } @@ -373,54 +387,55 @@ public void startCell(TableRenderContext context) { */ protected String getStyleClass(TableRenderContext context) { String styleClass = null; - + String type = context.getCellType(); - + StyleClassResolver resolver; - + if (LABEL.equals(type) && context.getAxis() == Axis.FILTER) { resolver = styleClassResolvers.get(VALUE); } else { resolver = styleClassResolvers.get(type); } - + if (resolver != null) { styleClass = resolver.resolve(context); } - + return styleClass; } /** - * @see org.pivot4j.ui.RenderCallback#renderCommands(org.pivot4j.ui.RenderContext, + * @see + * org.pivot4j.ui.RenderCallback#renderCommands(org.pivot4j.ui.RenderContext, * java.util.List) */ @Override public void renderCommands(TableRenderContext context, - List> commands) { + List> commands) { if (expressionFactory != null) { for (UICommand command : commands) { UICommandParameters parameters = command .createParameters(context); - + CommandButton button = new CommandButton(); // JSF requires an unique id for command components. button.setId("btn-" + commandIndex++); - + button.setTitle(command.getDescription()); - + String icon = null; - + String mode = command.getMode(context); if (mode == null) { icon = iconMap.get(command.getName()); } else { icon = iconMap.get(command.getName() + "-" + mode); } - + button.setIcon(icon); - + MethodExpression expression = expressionFactory .createMethodExpression(facesContext.getELContext(), "#{viewHandler.executeCommand}", Void.class, @@ -429,62 +444,63 @@ public void renderCommands(TableRenderContext context, button.setUpdate(updateTarget); button.setOncomplete("onViewChanged()"); button.setProcess("@this"); - + UIParameter commandParam = new UIParameter(); commandParam.setName("command"); commandParam.setValue(command.getName()); button.getChildren().add(commandParam); - + UIParameter axisParam = new UIParameter(); axisParam.setName("axis"); axisParam.setValue(parameters.getAxisOrdinal()); button.getChildren().add(axisParam); - + UIParameter positionParam = new UIParameter(); positionParam.setName("position"); positionParam.setValue(parameters.getPositionOrdinal()); button.getChildren().add(positionParam); - + UIParameter memberParam = new UIParameter(); memberParam.setName("member"); memberParam.setValue(parameters.getMemberOrdinal()); button.getChildren().add(memberParam); - + UIParameter hierarchyParam = new UIParameter(); hierarchyParam.setName("hierarchy"); hierarchyParam.setValue(parameters.getHierarchyOrdinal()); button.getChildren().add(hierarchyParam); - + if (parameters.getCellCoordinate() != null) { Integer[] coords = ArrayUtils.toObject(parameters.getCellCoordinate()); - + UIParameter cellParam = new UIParameter(); cellParam.setName("cell"); cellParam.setValue(StringUtils.join(coords, ',')); button.getChildren().add(cellParam); } - + column.getChildren().add(button); } } } /** - * @see org.pivot4j.ui.RenderCallback#renderContent(org.pivot4j.ui.RenderContext, + * @see + * org.pivot4j.ui.RenderCallback#renderContent(org.pivot4j.ui.RenderContext, * java.lang.String, java.lang.Double) */ @Override public void renderContent(TableRenderContext context, String label, - Double value) { + Double value) { ExpressionContext elContext = context.getExpressionContext(); - + elContext.put("label", label); elContext.put("value", value); - + String labelText; - + RenderPropertyUtils propertyUtils = getRenderPropertyUtils(); - + try { labelText = StringUtils.defaultIfEmpty( propertyUtils.getString("label", @@ -493,69 +509,83 @@ public void renderContent(TableRenderContext context, String label, elContext.remove("label"); elContext.remove("value"); } - + Cell cell = context.getCell(); - + if (scenarioEnabled && context.getCellType().equals(VALUE) && cell != null) { Inplace inplace = new Inplace(); inplace.setId("inplace-" + context.getCell().getOrdinal()); inplace.setLabel(labelText); inplace.setEditor(true); - + InputText input = new InputText(); input.setId("input-" + context.getCell().getOrdinal()); input.setValue(value); input.setConverter(new DoubleConverter()); - + MethodExpression expression = expressionFactory .createMethodExpression(facesContext.getELContext(), "#{viewHandler.updateCell}", Void.class, new Class[0]); - + AjaxBehavior behavior = new AjaxBehavior(); behavior.addAjaxBehaviorListener(new AjaxBehaviorListenerImpl( expression, expression)); behavior.setProcess("@this"); behavior.setUpdate("@form"); - + UIParameter commandParam = new UIParameter(); commandParam.setName("cell"); commandParam.setValue(Integer.toString(cell.getOrdinal())); - + inplace.addClientBehavior("save", behavior); inplace.getChildren().add(commandParam); inplace.getChildren().add(input); - + column.getChildren().add(inplace); } else { HtmlOutputText text = new HtmlOutputText(); - String id = "txt-" + text.hashCode(); - + + UUID uuid = Generators.timeBasedGenerator().generate(); + + String id = "txt-" + uuid.toString(); text.setId(id); - text.setValue(labelText); - + + if (labelText.length() > 2 && labelText.charAt(0) == '|') { + StringTokenizer st = new StringTokenizer(labelText, "|"); + if (st.hasMoreTokens()) { + text.setValue(st.nextToken()); + } + if (st.hasMoreTokens()) { + text.setStyle(st.nextToken()); + } + } else { + text.setValue(labelText); + } + if (context.getMember() != null) { text.setTitle(context.getMember().getUniqueName()); } - + String link = propertyUtils.getString("link", context.getRenderPropertyCategory(), null); - + if (link == null) { column.getChildren().add(text); } else { HtmlOutputLink anchor = new HtmlOutputLink(); anchor.setValue(link); anchor.getChildren().add(text); - + column.getChildren().add(anchor); } } } /** - * @see org.pivot4j.ui.table.TableRenderCallback#endCell(org.pivot4j.ui.table.TableRenderContext) + * @see + * org.pivot4j.ui.table.TableRenderCallback#endCell(org.pivot4j.ui.table.TableRenderContext) */ @Override public void endCell(TableRenderContext context) { @@ -564,7 +594,8 @@ public void endCell(TableRenderContext context) { } /** - * @see org.pivot4j.ui.table.TableRenderCallback#endRow(org.pivot4j.ui.table.TableRenderContext) + * @see + * org.pivot4j.ui.table.TableRenderCallback#endRow(org.pivot4j.ui.table.TableRenderContext) */ @Override public void endRow(TableRenderContext context) { @@ -573,19 +604,21 @@ public void endRow(TableRenderContext context) { } else { header.getChildren().add(row); } - + this.row = null; } /** - * @see org.pivot4j.ui.table.TableRenderCallback#endBody(org.pivot4j.ui.table.TableRenderContext) + * @see + * org.pivot4j.ui.table.TableRenderCallback#endBody(org.pivot4j.ui.table.TableRenderContext) */ @Override public void endBody(TableRenderContext context) { } /** - * @see org.pivot4j.ui.table.TableRenderCallback#endTable(org.pivot4j.ui.table.TableRenderContext) + * @see + * org.pivot4j.ui.table.TableRenderCallback#endTable(org.pivot4j.ui.table.TableRenderContext) */ @Override public void endTable(TableRenderContext context) { @@ -594,17 +627,18 @@ public void endTable(TableRenderContext context) { } else { gridPanel.getChildren().add(grid); } - + this.grid = null; } /** - * @see org.pivot4j.ui.RenderCallback#endRender(org.pivot4j.ui.RenderContext) + * @see + * org.pivot4j.ui.RenderCallback#endRender(org.pivot4j.ui.RenderContext) */ @Override public void endRender(TableRenderContext context) { ResourceBundle resources = context.getResourceBundle(); - + MessageFormat mf = new MessageFormat( resources.getString("error.property.expression.title")); @@ -612,41 +646,41 @@ public void endRender(TableRenderContext context) { for (String category : context.getRenderProperties().keySet()) { Map errors = getRenderPropertyUtils() .getLastErrors(category); - + for (String property : errors.keySet()) { String title = mf.format(new String[]{resources - .getString("properties." + property)}); - + .getString("properties." + property)}); + EvaluationFailedException e = errors.get(property); - + facesContext.addMessage(null, new FacesMessage( FacesMessage.SEVERITY_ERROR, title, e.getMessage())); - + if (logger.isWarnEnabled()) { logger.warn(title, e); } } } - + this.commandIndex = 0; this.scenarioEnabled = false; - + super.endRender(context); } - + interface StyleClassResolver { - + String resolve(TableRenderContext context); } - + static class TitleStyleClassResolver implements StyleClassResolver { - + @Override public String resolve(TableRenderContext context) { String styleClass; - + String type = context.getCellType(); - + if (context.getAxis() == Axis.COLUMNS) { styleClass = "col-hdr-cell"; } else if (type.equals(LABEL) @@ -655,17 +689,17 @@ public String resolve(TableRenderContext context) { } else { styleClass = "ui-widget-header"; } - + return styleClass; } } - + static class ValueStyleClassResolver implements StyleClassResolver { - + @Override public String resolve(TableRenderContext context) { String styleClass; - + if (context.getAggregator() == null) { // PrimeFaces' Row class doesn't have the styleClass property. if (context.getRowIndex() % 2 == 0) { @@ -675,32 +709,32 @@ public String resolve(TableRenderContext context) { } } else { styleClass = "ui-widget-header agg-cell"; - + if (context.getAxis() == Axis.COLUMNS) { styleClass += " col-agg-cell"; } else if (context.getAxis() == Axis.ROWS) { styleClass += " row-agg-cell"; } } - + return styleClass; } } - + static class AggregationStyleClassResolver implements StyleClassResolver { - + @Override public String resolve(TableRenderContext context) { String styleClass; - + if (context.getAxis() == Axis.ROWS) { styleClass = "ui-widget-header "; } else { styleClass = ""; } - + styleClass += "agg-title"; - + return styleClass; } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/PivotExportHandler.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/PivotExportHandler.java index c13fcf40..f226ddfd 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/PivotExportHandler.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/PivotExportHandler.java @@ -1,416 +1,405 @@ -package org.pivot4j.analytics.ui; - -import java.io.IOException; -import java.io.OutputStream; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.MissingResourceException; -import java.util.ResourceBundle; - -import javax.faces.bean.ManagedBean; -import javax.faces.bean.ManagedProperty; -import javax.faces.bean.RequestScoped; -import javax.faces.context.ExternalContext; -import javax.faces.context.FacesContext; -import javax.faces.model.SelectItem; -import javax.print.attribute.standard.MediaSize; -import javax.print.attribute.standard.MediaSizeName; -import javax.print.attribute.standard.OrientationRequested; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.StringUtils; -import org.pivot4j.PivotModel; -import org.pivot4j.ui.fop.FopExporter; -import org.pivot4j.ui.poi.ExcelExporter; -import org.pivot4j.ui.poi.Format; -import org.pivot4j.ui.table.TableRenderer; - -@ManagedBean(name = "pivotExportHandler") -@RequestScoped -public class PivotExportHandler { - - @ManagedProperty(value = "#{pivotStateManager.model}") - private PivotModel model; - - @ManagedProperty(value = "#{viewHandler}") - private ViewHandler viewHandler; - - private boolean showHeader = true; - - private String headerText; - - private boolean showFooter = true; - - private String footerText; - - private int paperSize = MediaSizeName.ISO_A4.getValue(); - - private List paperSizes; - - private Orientation orientation = Orientation.Portrait; - - private List orientations; - - private int fontSize = 8; - - private int headerFontSize = 10; - - private int footerFontSize = 10; - - public enum Orientation { - Portrait { - @Override - OrientationRequested getValue() { - return OrientationRequested.PORTRAIT; - } - }, - Landscape { - @Override - OrientationRequested getValue() { - return OrientationRequested.LANDSCAPE; - } - }; - - abstract OrientationRequested getValue(); - }; - - /** - * @return the viewHandler - */ - public ViewHandler getViewHandler() { - return viewHandler; - } - - /** - * @param viewHandler - * the viewHandler to set - */ - public void setViewHandler(ViewHandler viewHandler) { - this.viewHandler = viewHandler; - } - - /** - * @return the model - */ - public PivotModel getModel() { - return model; - } - - /** - * @param model - * the model to set - */ - public void setModel(PivotModel model) { - this.model = model; - } - - /** - * @return the showHeader - */ - public boolean getShowHeader() { - return showHeader; - } - - /** - * @param showHeader - * the showHeader to set - */ - public void setShowHeader(boolean showHeader) { - this.showHeader = showHeader; - } - - /** - * @return the headerText - */ - public String getHeaderText() { - return headerText; - } - - /** - * @param headerText - * the headerText to set - */ - public void setHeaderText(String headerText) { - this.headerText = headerText; - } - - /** - * @return the showFooter - */ - public boolean getShowFooter() { - return showFooter; - } - - /** - * @param showFooter - * the showFooter to set - */ - public void setShowFooter(boolean showFooter) { - this.showFooter = showFooter; - } - - /** - * @return the footerText - */ - public String getFooterText() { - return footerText; - } - - /** - * @param footerText - * the footerText to set - */ - public void setFooterText(String footerText) { - this.footerText = footerText; - } - - /** - * @return the paperSize - */ - public int getPaperSize() { - return paperSize; - } - - /** - * @param paperSize - * the paperSize to set - */ - public void setPaperSize(int paperSize) { - this.paperSize = paperSize; - } - - /** - * @return the paperSizes - * @throws IllegalAccessException - * @throws IllegalArgumentException - */ - public List getPaperSizes() throws IllegalAccessException { - if (paperSizes == null) { - this.paperSizes = new ArrayList(); - - Field[] fields = MediaSizeName.class.getFields(); - for (Field field : fields) { - String name = field.getName(); - MediaSizeName media = (MediaSizeName) field.get(null); - paperSizes.add(new SelectItem( - Integer.toString(media.getValue()), name)); - } - } - - return paperSizes; - } - - /** - * @return the orientation - */ - public Orientation getOrientation() { - return orientation; - } - - /** - * @param orientation - * the orientation to set - */ - public void setOrientation(Orientation orientation) { - this.orientation = orientation; - } - - /** - * @return the orientations - */ - public List getOrientations() { - if (orientations == null) { - FacesContext context = FacesContext.getCurrentInstance(); - - ResourceBundle bundle = context.getApplication().getResourceBundle( - context, "msg"); - - this.orientations = new ArrayList(); - - for (Orientation orient : Orientation.values()) { - String label; - - try { - label = bundle - .getString("label.pdfExport.page.orientation." - + orient.name().toLowerCase()); - } catch (MissingResourceException e) { - label = orient.name(); - } - - orientations.add(new SelectItem(orient, label)); - } - } - - return orientations; - } - - /** - * @return the fontSize - */ - public int getFontSize() { - return fontSize; - } - - /** - * @param fontSize - * the fontSize to set - */ - public void setFontSize(int fontSize) { - this.fontSize = fontSize; - } - - /** - * @return the headerFontSize - */ - public int getHeaderFontSize() { - return headerFontSize; - } - - /** - * @param headerFontSize - * the headerFontSize to set - */ - public void setHeaderFontSize(int headerFontSize) { - this.headerFontSize = headerFontSize; - } - - /** - * @return the footerFontSize - */ - public int getFooterFontSize() { - return footerFontSize; - } - - /** - * @param footerFontSize - * the footerFontSize to set - */ - public void setFooterFontSize(int footerFontSize) { - this.footerFontSize = footerFontSize; - } - - public void exportExcel() throws IOException { - FacesContext context = FacesContext.getCurrentInstance(); - - ExternalContext externalContext = context.getExternalContext(); - - Map parameters = externalContext - .getRequestParameterMap(); - - Format format; - - if (parameters.containsKey("format")) { - format = Format.valueOf(parameters.get("format")); - } else { - format = Format.HSSF; - } - - exportExcel(format); - - context.responseComplete(); - } - - /** - * @param format - * @throws IOException - */ - protected void exportExcel(Format format) throws IOException { - FacesContext context = FacesContext.getCurrentInstance(); - - String disposition = String.format("attachment; filename=\"%s.%s\"", - model.getCube().getName(), format.getExtension()); - - ExternalContext externalContext = context.getExternalContext(); - externalContext.setResponseHeader("Content-Disposition", disposition); - - TableRenderer renderer = viewHandler.getRenderer(); - - boolean renderSlicer = renderer.getRenderSlicer(); - boolean inline = renderer.getShowSlicerMembersInline(); - - OutputStream out = externalContext.getResponseOutputStream(); - - ExcelExporter exporter = new ExcelExporter(out); - exporter.setFormat(format); - - externalContext.setResponseContentType(exporter.getContentType()); - - try { - renderer.setRenderSlicer(viewHandler.getRenderSlicer()); - renderer.setShowSlicerMembersInline(false); - - renderer.render(model, exporter); - } finally { - renderer.setRenderSlicer(renderSlicer); - renderer.setShowSlicerMembersInline(inline); - - out.flush(); - IOUtils.closeQuietly(out); - } - } - - public void exportPdf() throws IOException, IllegalAccessException { - TableRenderer renderer = viewHandler.getRenderer(); - - FacesContext context = FacesContext.getCurrentInstance(); - - String disposition = String.format("attachment; filename=\"%s.%s\"", - model.getCube().getName(), "pdf"); - - ExternalContext externalContext = context.getExternalContext(); - - OutputStream out = externalContext.getResponseOutputStream(); - - FopExporter exporter = new FopExporter(out); - exporter.setShowHeader(showHeader); - - if (StringUtils.isNotBlank(headerText)) { - exporter.setTitleText(headerText); - } - - exporter.setShowFooter(showFooter); - - if (StringUtils.isNotBlank(footerText)) { - exporter.setFooterText(footerText); - } - - exporter.setFontSize(fontSize + "pt"); - exporter.setTitleFontSize(headerFontSize + "pt"); - exporter.setFooterFontSize(footerFontSize + "pt"); - exporter.setOrientation(orientation.getValue()); - - MediaSize mediaSize = null; - - Field[] fields = MediaSizeName.class.getFields(); - for (Field field : fields) { - MediaSizeName name = (MediaSizeName) field.get(null); - if (name.getValue() == paperSize) { - mediaSize = MediaSize.getMediaSizeForName(name); - break; - } - } - - exporter.setMediaSize(mediaSize); - - externalContext.setResponseContentType(exporter.getContentType()); - externalContext.setResponseHeader("Content-Disposition", disposition); - - boolean renderSlicer = renderer.getRenderSlicer(); - - try { - renderer.setRenderSlicer(viewHandler.getRenderSlicer()); - - renderer.render(model, exporter); - } finally { - renderer.setRenderSlicer(renderSlicer); - - out.flush(); - IOUtils.closeQuietly(out); - } - - context.responseComplete(); - } -} +package org.pivot4j.analytics.ui; + +import java.io.IOException; +import java.io.OutputStream; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +import javax.faces.bean.ManagedBean; +import javax.faces.bean.ManagedProperty; +import javax.faces.bean.RequestScoped; +import javax.faces.context.ExternalContext; +import javax.faces.context.FacesContext; +import javax.faces.model.SelectItem; +import javax.print.attribute.standard.MediaSize; +import javax.print.attribute.standard.MediaSizeName; +import javax.print.attribute.standard.OrientationRequested; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.pivot4j.PivotModel; +import org.pivot4j.ui.fop.FopExporter; +import org.pivot4j.ui.poi.ExcelExporter; +import org.pivot4j.ui.poi.Format; +import org.pivot4j.ui.table.TableRenderer; + +@ManagedBean(name = "pivotExportHandler") +@RequestScoped +public class PivotExportHandler { + + @ManagedProperty(value = "#{pivotStateManager.model}") + private PivotModel model; + + @ManagedProperty(value = "#{viewHandler}") + private ViewHandler viewHandler; + + private boolean showHeader = true; + + private String headerText; + + private boolean showFooter = true; + + private String footerText; + + private int paperSize = MediaSizeName.ISO_A4.getValue(); + + private List paperSizes; + + private Orientation orientation = Orientation.Portrait; + + private List orientations; + + private int fontSize = 8; + + private int headerFontSize = 10; + + private int footerFontSize = 10; + + public enum Orientation { + Portrait { + @Override + OrientationRequested getValue() { + return OrientationRequested.PORTRAIT; + } + }, + Landscape { + @Override + OrientationRequested getValue() { + return OrientationRequested.LANDSCAPE; + } + }; + + abstract OrientationRequested getValue(); + }; + + /** + * @return the viewHandler + */ + public ViewHandler getViewHandler() { + return viewHandler; + } + + /** + * @param viewHandler the viewHandler to set + */ + public void setViewHandler(ViewHandler viewHandler) { + this.viewHandler = viewHandler; + } + + /** + * @return the model + */ + public PivotModel getModel() { + return model; + } + + /** + * @param model the model to set + */ + public void setModel(PivotModel model) { + this.model = model; + } + + /** + * @return the showHeader + */ + public boolean getShowHeader() { + return showHeader; + } + + /** + * @param showHeader the showHeader to set + */ + public void setShowHeader(boolean showHeader) { + this.showHeader = showHeader; + } + + /** + * @return the headerText + */ + public String getHeaderText() { + return headerText; + } + + /** + * @param headerText the headerText to set + */ + public void setHeaderText(String headerText) { + this.headerText = headerText; + } + + /** + * @return the showFooter + */ + public boolean getShowFooter() { + return showFooter; + } + + /** + * @param showFooter the showFooter to set + */ + public void setShowFooter(boolean showFooter) { + this.showFooter = showFooter; + } + + /** + * @return the footerText + */ + public String getFooterText() { + return footerText; + } + + /** + * @param footerText the footerText to set + */ + public void setFooterText(String footerText) { + this.footerText = footerText; + } + + /** + * @return the paperSize + */ + public int getPaperSize() { + return paperSize; + } + + /** + * @param paperSize the paperSize to set + */ + public void setPaperSize(int paperSize) { + this.paperSize = paperSize; + } + + /** + * @return the paperSizes + * @throws IllegalAccessException + * @throws IllegalArgumentException + */ + public List getPaperSizes() throws IllegalAccessException { + if (paperSizes == null) { + this.paperSizes = new ArrayList(); + + Field[] fields = MediaSizeName.class.getFields(); + for (Field field : fields) { + String name = field.getName(); + MediaSizeName media = (MediaSizeName) field.get(null); + paperSizes.add(new SelectItem( + Integer.toString(media.getValue()), name)); + } + } + + return paperSizes; + } + + /** + * @return the orientation + */ + public Orientation getOrientation() { + return orientation; + } + + /** + * @param orientation the orientation to set + */ + public void setOrientation(Orientation orientation) { + this.orientation = orientation; + } + + /** + * @return the orientations + */ + public List getOrientations() { + if (orientations == null) { + FacesContext context = FacesContext.getCurrentInstance(); + + ResourceBundle bundle = context.getApplication().getResourceBundle( + context, "msg"); + + this.orientations = new ArrayList(); + + for (Orientation orient : Orientation.values()) { + String label; + + try { + label = bundle + .getString("label.pdfExport.page.orientation." + + orient.name().toLowerCase()); + } catch (MissingResourceException e) { + label = orient.name(); + } + + orientations.add(new SelectItem(orient, label)); + } + } + + return orientations; + } + + /** + * @return the fontSize + */ + public int getFontSize() { + return fontSize; + } + + /** + * @param fontSize the fontSize to set + */ + public void setFontSize(int fontSize) { + this.fontSize = fontSize; + } + + /** + * @return the headerFontSize + */ + public int getHeaderFontSize() { + return headerFontSize; + } + + /** + * @param headerFontSize the headerFontSize to set + */ + public void setHeaderFontSize(int headerFontSize) { + this.headerFontSize = headerFontSize; + } + + /** + * @return the footerFontSize + */ + public int getFooterFontSize() { + return footerFontSize; + } + + /** + * @param footerFontSize the footerFontSize to set + */ + public void setFooterFontSize(int footerFontSize) { + this.footerFontSize = footerFontSize; + } + + public void exportExcel() throws IOException { + FacesContext context = FacesContext.getCurrentInstance(); + + ExternalContext externalContext = context.getExternalContext(); + + Map parameters = externalContext + .getRequestParameterMap(); + + Format format; + + if (parameters.containsKey("format")) { + format = Format.valueOf(parameters.get("format")); + } else { + format = Format.HSSF; + } + + exportExcel(format); + + context.responseComplete(); + } + + /** + * @param format + * @throws IOException + */ + protected void exportExcel(Format format) throws IOException { + FacesContext context = FacesContext.getCurrentInstance(); + + String disposition = String.format("attachment; filename=\"%s.%s\"", + model.getCube().getName(), format.getExtension()); + + ExternalContext externalContext = context.getExternalContext(); + externalContext.setResponseHeader("Content-Disposition", disposition); + + TableRenderer renderer = viewHandler.getRenderer(); + + boolean renderSlicer = renderer.getRenderSlicer(); + boolean inline = renderer.getShowSlicerMembersInline(); + + OutputStream out = externalContext.getResponseOutputStream(); + + ExcelExporter exporter = new ExcelExporter(out); + exporter.setFormat(format); + + externalContext.setResponseContentType(exporter.getContentType()); + + try { + renderer.setRenderSlicer(viewHandler.getRenderSlicer()); + renderer.setShowSlicerMembersInline(false); + + renderer.render(model, exporter); + } finally { + renderer.setRenderSlicer(renderSlicer); + renderer.setShowSlicerMembersInline(inline); + + out.flush(); + IOUtils.closeQuietly(out); + } + } + + public void exportPdf() throws IOException, IllegalAccessException { + TableRenderer renderer = viewHandler.getRenderer(); + + FacesContext context = FacesContext.getCurrentInstance(); + + String disposition = String.format("attachment; filename=\"%s.%s\"", + model.getCube().getName(), "pdf"); + + ExternalContext externalContext = context.getExternalContext(); + + OutputStream out = externalContext.getResponseOutputStream(); + + FopExporter exporter = new FopExporter(out); + exporter.setShowHeader(showHeader); + + if (StringUtils.isNotBlank(headerText)) { + exporter.setTitleText(headerText); + } + + exporter.setShowFooter(showFooter); + + if (StringUtils.isNotBlank(footerText)) { + exporter.setFooterText(footerText); + } + + exporter.setFontSize(fontSize + "pt"); + exporter.setTitleFontSize(headerFontSize + "pt"); + exporter.setFooterFontSize(footerFontSize + "pt"); + exporter.setOrientation(orientation.getValue()); + + MediaSize mediaSize = null; + + Field[] fields = MediaSizeName.class.getFields(); + for (Field field : fields) { + MediaSizeName name = (MediaSizeName) field.get(null); + if (name.getValue() == paperSize) { + mediaSize = MediaSize.getMediaSizeForName(name); + break; + } + } + + exporter.setMediaSize(mediaSize); + + externalContext.setResponseContentType(exporter.getContentType()); + externalContext.setResponseHeader("Content-Disposition", disposition); + + boolean renderSlicer = renderer.getRenderSlicer(); + + try { + renderer.setRenderSlicer(viewHandler.getRenderSlicer()); + + renderer.render(model, exporter); + } finally { + renderer.setRenderSlicer(renderSlicer); + + out.flush(); + IOUtils.closeQuietly(out); + } + + context.responseComplete(); + } +} diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/PivotStateManager.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/PivotStateManager.java index 7a588840..8950b10b 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/PivotStateManager.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/PivotStateManager.java @@ -26,201 +26,206 @@ @ViewScoped public class PivotStateManager implements Serializable { - private static final long serialVersionUID = -146698046524588064L; - - private Logger log = LoggerFactory.getLogger(getClass()); - - @ManagedProperty(value = "#{settings}") - private Settings settings; - - @ManagedProperty(value = "#{viewStateHolder}") - private ViewStateHolder viewStateHolder; - - private String viewId; - - @PostConstruct - protected void initialize() { - FacesContext context = FacesContext.getCurrentInstance(); - - ExternalContext externalContext = context.getExternalContext(); - Flash flash = externalContext.getFlash(); - - Map parameters = externalContext - .getRequestParameterMap(); - - this.viewId = parameters.get(settings.getViewParameterName()); - - if (viewId == null) { - this.viewId = (String) flash.get("viewId"); - } - - ViewState state = null; - - if (viewId != null) { - state = viewStateHolder.getState(viewId); - } - - if (state == null) { - ProjectStage stage = context.getApplication().getProjectStage(); - - if (stage == ProjectStage.UnitTest) { - state = viewStateHolder.createNewState(); - viewStateHolder.registerState(state); - - this.viewId = state.getId(); - } else { - throw new FacesException("No view state data is available : " - + viewId); - } - } - - if (log.isInfoEnabled()) { - log.info("Using an existing view state : {}", viewId); - } - } - - @PreDestroy - public void destroy() { - viewStateHolder.unregisterState(viewId); - } - - /** - * @return the viewId - */ - public String getViewId() { - return viewId; - } - - public ViewState getState() { - return viewStateHolder.getState(viewId); - } - - /** - * @return the model - */ - public PivotModel getModel() { - ViewState state = getState(); - if (state == null) { - return null; - } - - return state.getModel(); - } - - /** - * @return the readOnly - */ - public boolean isReadOnly() { - ViewState state = getState(); - if (state == null) { - return true; - } - - return state.isReadOnly(); - } - - /** - * @return the dirty - */ - public boolean isDirty() { - ViewState state = getState(); - if (state == null) { - return false; - } - - return state.isDirty(); - } - - /** - * @return the settings - */ - public Settings getSettings() { - return settings; - } - - /** - * @param settings - * the settings to set - */ - public void setSettings(Settings settings) { - this.settings = settings; - } - - /** - * @return the viewStateHolder - */ - public ViewStateHolder getViewStateHolder() { - return viewStateHolder; - } - - /** - * @param viewStateHolder - * the viewStateHolder to set - */ - public void setViewStateHolder(ViewStateHolder viewStateHolder) { - this.viewStateHolder = viewStateHolder; - } - - /** - * @return the rendererState - */ - public Serializable getRendererState() { - ViewState state = getState(); - if (state == null) { - return null; - } - - return state.getRendererState(); - } - - /** - * @param rendererState - * the rendererState to set - */ - public void setRendererState(Serializable rendererState) { - ViewState state = getState(); - if (state == null) { - return; - } - - state.setRendererState(rendererState); - } - - /** - * @return the chartState - */ - public Serializable getChartState() { - ViewState state = getState(); - if (state == null) { - return null; - } - - return state.getChartState(); - } - - /** - * @param chartState - * the chartState to set - */ - public void setChartState(Serializable chartState) { - ViewState state = getState(); - if (state == null) { - return; - } - - state.setChartState(chartState); - } - - public ConnectionInfo getConnectionInfo() { - ViewState state = getState(); - if (state == null) { - return null; - } - - return state.getConnectionInfo(); - } - - public void keepAlive() { - viewStateHolder.keepAlive(viewId); - } + private static final long serialVersionUID = -146698046524588064L; + + private Logger log = LoggerFactory.getLogger(getClass()); + + @ManagedProperty(value = "#{settings}") + private Settings settings; + + @ManagedProperty(value = "#{viewStateHolder}") + private ViewStateHolder viewStateHolder; + + private String viewId; + + @PostConstruct + protected void initialize() { + FacesContext context = FacesContext.getCurrentInstance(); + + ExternalContext externalContext = context.getExternalContext(); + Flash flash = externalContext.getFlash(); + + Map parameters = externalContext + .getRequestParameterMap(); + + this.viewId = parameters.get(settings.getViewParameterName()); + + if (viewId == null) { + this.viewId = (String) flash.get("viewId"); + } + + ViewState state = null; + + if (viewId != null) { + state = viewStateHolder.getState(viewId); + } + + if (state == null) { + ProjectStage stage = context.getApplication().getProjectStage(); + + if (stage == ProjectStage.UnitTest) { + state = viewStateHolder.createNewState(); + viewStateHolder.registerState(state); + + this.viewId = state.getId(); + } else { + throw new FacesException("No view state data is available : " + + viewId); + } + } + + if (log.isInfoEnabled()) { + log.info("Using an existing view state : {}", viewId); + } + } + + @PreDestroy + public void destroy() { + viewStateHolder.unregisterState(viewId); + } + + /** + * @return the viewId + */ + public String getViewId() { + return viewId; + } + + public ViewState getState() { + return viewStateHolder.getState(viewId); + } + + /** + * @return the model + */ + public PivotModel getModel() { + ViewState state = getState(); + if (state == null) { + return null; + } + + return state.getModel(); + } + + /** + * @return the readOnly + */ + public boolean isReadOnly() { + ViewState state = getState(); + if (state == null) { + return true; + } + + return state.isReadOnly(); + } + + /** + * @return the dirty + */ + public boolean isDirty() { + ViewState state = getState(); + if (state == null) { + return false; + } + + return state.isDirty(); + } + + public boolean isEnableMdx() { + ViewState state = getState(); + if (state == null) { + return true; + } + + return state.isEnableMdx(); + } + + /** + * @return the settings + */ + public Settings getSettings() { + return settings; + } + + /** + * @param settings the settings to set + */ + public void setSettings(Settings settings) { + this.settings = settings; + } + + /** + * @return the viewStateHolder + */ + public ViewStateHolder getViewStateHolder() { + return viewStateHolder; + } + + /** + * @param viewStateHolder the viewStateHolder to set + */ + public void setViewStateHolder(ViewStateHolder viewStateHolder) { + this.viewStateHolder = viewStateHolder; + } + + /** + * @return the rendererState + */ + public Serializable getRendererState() { + ViewState state = getState(); + if (state == null) { + return null; + } + + return state.getRendererState(); + } + + /** + * @param rendererState the rendererState to set + */ + public void setRendererState(Serializable rendererState) { + ViewState state = getState(); + if (state == null) { + return; + } + + state.setRendererState(rendererState); + } + + /** + * @return the chartState + */ + public Serializable getChartState() { + ViewState state = getState(); + if (state == null) { + return null; + } + + return state.getChartState(); + } + + /** + * @param chartState the chartState to set + */ + public void setChartState(Serializable chartState) { + ViewState state = getState(); + if (state == null) { + return; + } + + state.setChartState(chartState); + } + + public ConnectionInfo getConnectionInfo() { + ViewState state = getState(); + if (state == null) { + return null; + } + + return state.getConnectionInfo(); + } + + public void keepAlive() { + viewStateHolder.keepAlive(viewId); + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/PropertiesHandler.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/PropertiesHandler.java index d0fbcc5a..ecf42ce8 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/PropertiesHandler.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/PropertiesHandler.java @@ -37,516 +37,509 @@ @RequestScoped public class PropertiesHandler { - @ManagedProperty(value = "#{propertyDescriptorFactory}") - private PropertyDescriptorFactory descriptorFactory; + @ManagedProperty(value = "#{propertyDescriptorFactory}") + private PropertyDescriptorFactory descriptorFactory; - @ManagedProperty(value = "#{viewHandler}") - private ViewHandler viewHandler; + @ManagedProperty(value = "#{viewHandler}") + private ViewHandler viewHandler; - private ResourceBundle bundle; + private ResourceBundle bundle; - private PropertyDescriptor descriptor; + private PropertyDescriptor descriptor; - private PanelMenu menu; + private PanelMenu menu; - private UIComponent editorPanel; + private UIComponent editorPanel; - private Object value; + private Object value; - private String expression; + private String expression; - @PostConstruct - protected void initialize() { - FacesContext context = FacesContext.getCurrentInstance(); + @PostConstruct + protected void initialize() { + FacesContext context = FacesContext.getCurrentInstance(); - this.bundle = context.getApplication() - .getResourceBundle(context, "msg"); + this.bundle = context.getApplication() + .getResourceBundle(context, "msg"); - String key = getKey(); - PropertyCategory category = getCategory(); + String key = getKey(); + PropertyCategory category = getCategory(); - if (key != null && category != null) { - this.descriptor = descriptorFactory.getDescriptor(category, key); - } - } + if (key != null && category != null) { + this.descriptor = descriptorFactory.getDescriptor(category, key); + } + } - /** - * @return bundle - */ - protected ResourceBundle getBundle() { - return bundle; - } + /** + * @return bundle + */ + protected ResourceBundle getBundle() { + return bundle; + } - public String getName() { - if (descriptor == null) { - return null; - } + public String getName() { + if (descriptor == null) { + return null; + } - FacesContext context = FacesContext.getCurrentInstance(); - return descriptor.getName(context); - } + FacesContext context = FacesContext.getCurrentInstance(); + return descriptor.getName(context); + } - public String getDescription() { - if (descriptor == null) { - return null; - } + public String getDescription() { + if (descriptor == null) { + return null; + } - FacesContext context = FacesContext.getCurrentInstance(); - return descriptor.getDescription(context); - } + FacesContext context = FacesContext.getCurrentInstance(); + return descriptor.getDescription(context); + } - public String getCategoryName() { - if (descriptor == null) { - return null; - } + public String getCategoryName() { + if (descriptor == null) { + return null; + } - return bundle.getString("properties.category." - + descriptor.getCategory().name()); - } + return bundle.getString("properties.category." + + descriptor.getCategory().name()); + } - public void selectProperty() { - FacesContext context = FacesContext.getCurrentInstance(); + public void selectProperty() { + FacesContext context = FacesContext.getCurrentInstance(); - Map parameters = context.getExternalContext() - .getRequestParameterMap(); + Map parameters = context.getExternalContext() + .getRequestParameterMap(); - PropertyCategory category = PropertyCategory.valueOf(parameters - .get("category")); - String key = parameters.get("key"); + PropertyCategory category = PropertyCategory.valueOf(parameters + .get("category")); + String key = parameters.get("key"); - setKey(key); - setCategory(category); + setKey(key); + setCategory(category); - this.descriptor = descriptorFactory.getDescriptor(category, key); + this.descriptor = descriptorFactory.getDescriptor(category, key); - RenderPropertyList properties = getProperties(descriptor.getCategory()); - - SimpleRenderProperty property = (SimpleRenderProperty) properties - .getRenderProperty(descriptor.getKey()); + RenderPropertyList properties = getProperties(descriptor.getCategory()); + + SimpleRenderProperty property = (SimpleRenderProperty) properties + .getRenderProperty(descriptor.getKey()); - if (property == null) { - this.expression = null; - } else { - this.expression = property.getValue(); - } + if (property == null) { + this.expression = null; + } else { + this.expression = property.getValue(); + } - if (expression != null - && (expression.contains("${") || expression.contains("<#"))) { - setUseExpression(true); - } else { - setUseExpression(false); - } - - editorPanel.getChildren().clear(); - - PropertyEditor editor = descriptor.getEditor(); - - if (editor == null) { - this.value = property.getValue(); - } else { - Application application = context.getApplication(); - - ExpressionFactory factory = application.getExpressionFactory(); - - ValueExpression exp = factory.createValueExpression( - context.getELContext(), "#{propertiesHandler.value}", - Object.class); - - MethodExpression listener = factory.createMethodExpression( - context.getELContext(), - "#{propertiesHandler.onPropertyChange}", Void.TYPE, - new Class[0]); - - editor.createComponent(descriptor, editorPanel, exp, listener, - "button-bar"); - - this.value = editor.getValue(descriptor, properties); - } - - setDirty(false); - } - - public void onPropertyChange() { - setDirty(true); - } - - public void onEditorModeChange() { - RenderPropertyList properties = getProperties(getCategory()); - SimpleRenderProperty property = (SimpleRenderProperty) properties - .getRenderProperty(getKey()); - - if (getUseExpression()) { - if (expression == null) { - if (property == null) { - this.expression = null; - } else { - this.expression = property.getValue(); - } - } - } else { - PropertyEditor editor = descriptor.getEditor(); - - if (editor == null) { - this.value = null; - } else { - this.value = editor.getValue(descriptor, properties); - } - } - } - - /** - * @param category - * @return - */ - protected RenderPropertyList getProperties(PropertyCategory category) { - TableRenderer renderer = viewHandler.getRenderer(); - - RenderPropertyList properties = null; - - switch (category) { - case Header: - properties = renderer.getRenderProperties().get(HEADER); - break; - case Cell: - properties = renderer.getRenderProperties().get(CELL); - break; - default: - assert false; - } - - return properties; - } - - /** - * @param event - * @return - */ - public List complete(CompleteEvent event) { - List suggestions = new LinkedList(); - - suggestions.add("context: " + event.getContext()); - suggestions.add("token: " + event.getToken()); - - return suggestions; - } - - public void apply() { - RenderPropertyList properties = getProperties(descriptor.getCategory()); - - if (getUseExpression()) { - if (expression == null) { - properties.removeRenderProperty(descriptor.getKey()); - } else { - SimpleRenderProperty property = new SimpleRenderProperty( - descriptor.getKey(), expression); - properties.setRenderProperty(property); - } - } else { - PropertyEditor editor = descriptor.getEditor(); - editor.setValue(descriptor, properties, value); - } - - setDirty(false); - - viewHandler.render(); - } - - /** - * @return the menu - */ - public PanelMenu getMenu() { - return menu; - } - - /** - * @param menu - * the menu to set - */ - public void setMenu(PanelMenu menu) { - List children = menu.getChildren(); - - children.clear(); - children.add(createSubMenu(PropertyCategory.Header)); - children.add(createSubMenu(PropertyCategory.Cell)); - - this.menu = menu; - } - - /** - * @param category - * @return - */ - protected UISubmenu createSubMenu(PropertyCategory category) { - String postfix = category.name().toLowerCase(); - - UISubmenu categoryMenu = new UISubmenu(); - categoryMenu.setId("menu-" + postfix); - categoryMenu.setLabel(bundle.getString("properties.category." - + category.name())); - - UISubmenu colorMenu = new UISubmenu(); - colorMenu.setId("menu-color-" + postfix); - colorMenu.setLabel(bundle.getString("properties.category.color")); - colorMenu.setIcon("ui-icon-image"); - colorMenu.getChildren().add(createMenuItem(category, "fgColor")); - colorMenu.getChildren().add(createMenuItem(category, "bgColor")); - - categoryMenu.getChildren().add(colorMenu); - - UISubmenu fontMenu = new UISubmenu(); - fontMenu.setId("menu-font-" + postfix); - fontMenu.setLabel(bundle.getString("properties.category.font")); - fontMenu.setIcon("ui-icon-pencil"); - fontMenu.getChildren().add(createMenuItem(category, "fontFamily")); - fontMenu.getChildren().add(createMenuItem(category, "fontSize")); - fontMenu.getChildren().add(createMenuItem(category, "fontStyle")); - - categoryMenu.getChildren().add(fontMenu); - - categoryMenu.getChildren().add(createMenuItem(category, "label")); - categoryMenu.getChildren().add(createMenuItem(category, "link")); - categoryMenu.getChildren().add(createMenuItem(category, "styleClass")); - - return categoryMenu; - } - - /** - * @param category - * @param key - * @return - */ - protected UIMenuItem createMenuItem(PropertyCategory category, String key) { - PropertyDescriptor property = descriptorFactory.getDescriptor(category, - key); - - FacesContext context = FacesContext.getCurrentInstance(); - - Application application = context.getApplication(); - ExpressionFactory factory = application.getExpressionFactory(); - - UIMenuItem item = new UIMenuItem(); - item.setId("mi-" + key.toLowerCase() + "-" - + category.name().toLowerCase()); - item.setValue(property.getName(context)); - item.setTitle(property.getDescription(context)); - item.setIcon(property.getIcon()); - - if (category.equals(getCategory()) && key.equals(getKey())) { - item.setStyleClass("ui-state-highlight"); - } - - MethodExpression exp = factory.createMethodExpression( - context.getELContext(), "#{propertiesHandler.selectProperty}", - Void.TYPE, new Class[0]); - item.setActionExpression(exp); - item.setUpdate("content,button-bar,:growl"); - item.setOnclick("jQuery('.ui-menuitem-link').removeClass('ui-state-highlight'); " - + "jQuery(this).addClass('ui-state-highlight');"); - item.setOncomplete("applyThemeToCMEditor('.properties-config .CodeMirror')"); - - UIParameter keyParam = new UIParameter(); - keyParam.setName("key"); - keyParam.setValue(key); - - item.getChildren().add(keyParam); - - UIParameter categoryParam = new UIParameter(); - categoryParam.setName("category"); - categoryParam.setValue(category.name()); - - item.getChildren().add(categoryParam); - - return item; - } - - /** - * @return key - */ - public String getKey() { - FacesContext context = FacesContext.getCurrentInstance(); - - Map attributes = context.getViewRoot().getAttributes(); - - return (String) attributes.get("propertyKey"); - } - - /** - * @param key - */ - public void setKey(String key) { - FacesContext context = FacesContext.getCurrentInstance(); - - Map attributes = context.getViewRoot().getAttributes(); - attributes.put("propertyKey", key); - } - - /** - * @return category - */ - public PropertyCategory getCategory() { - FacesContext context = FacesContext.getCurrentInstance(); - - Map attributes = context.getViewRoot().getAttributes(); - - return (PropertyCategory) attributes.get("propertyCategory"); - } - - /** - * @param category - */ - public void setCategory(PropertyCategory category) { - FacesContext context = FacesContext.getCurrentInstance(); - - Map attributes = context.getViewRoot().getAttributes(); - attributes.put("propertyCategory", category); - } - - /** - * @return dirty - */ - public boolean isDirty() { - FacesContext context = FacesContext.getCurrentInstance(); - - Map attributes = context.getViewRoot().getAttributes(); - - Object attribute = attributes.get("propertyChanged"); - - return attribute != null && (Boolean) attribute; - } - - /** - * @param dirty - */ - public void setDirty(boolean dirty) { - FacesContext context = FacesContext.getCurrentInstance(); - - Map attributes = context.getViewRoot().getAttributes(); - attributes.put("propertyChanged", dirty); - } - - public boolean isSet() { - boolean isSet = false; - - if (descriptor != null) { - RenderProperty property = getProperties(getCategory()) - .getRenderProperty(getKey()); - isSet = property != null; - } - - return isSet; - } - - /** - * @return the useExpression - */ - public boolean getUseExpression() { - FacesContext context = FacesContext.getCurrentInstance(); - - Map attributes = context.getViewRoot().getAttributes(); - - Object attribute = attributes.get("useExpression"); - - return attribute != null && (Boolean) attribute; - } - - /** - * @param useExpression - * the useExpression to set - */ - public void setUseExpression(boolean useExpression) { - FacesContext context = FacesContext.getCurrentInstance(); - - Map attributes = context.getViewRoot().getAttributes(); - attributes.put("useExpression", useExpression); - } - - public void reset() { - this.value = null; - this.expression = null; - - setDirty(true); - setUseExpression(false); - } - - /** - * @return the descriptor - */ - public PropertyDescriptor getDescriptor() { - return descriptor; - } - - /** - * @return the descriptorFactory - */ - public PropertyDescriptorFactory getDescriptorFactory() { - return descriptorFactory; - } - - /** - * @param descriptorFactory - * the descriptorFactory to set - */ - public void setDescriptorFactory(PropertyDescriptorFactory descriptorFactory) { - this.descriptorFactory = descriptorFactory; - } - - /** - * @return the viewHandler - */ - public ViewHandler getViewHandler() { - return viewHandler; - } - - /** - * @param viewHandler - * the viewHandler to set - */ - public void setViewHandler(ViewHandler viewHandler) { - this.viewHandler = viewHandler; - } - - /** - * @return the editorPanel - */ - public UIComponent getEditorPanel() { - return editorPanel; - } - - /** - * @param editorPanel - * the editorPanel to set - */ - public void setEditorPanel(UIComponent editorPanel) { - this.editorPanel = editorPanel; - } - - /** - * @return the value - */ - public Object getValue() { - return value; - } - - /** - * @param value - * the value to set - */ - public void setValue(Object value) { - this.value = value; - } - - /** - * @return the expression - */ - public String getExpression() { - return expression; - } - - /** - * @param expression - * the expression to set - */ - public void setExpression(String expression) { - this.expression = expression; - } + if (expression != null + && (expression.contains("${") || expression.contains("<#"))) { + setUseExpression(true); + } else { + setUseExpression(false); + } + + editorPanel.getChildren().clear(); + + PropertyEditor editor = descriptor.getEditor(); + + if (editor == null) { + this.value = property.getValue(); + } else { + Application application = context.getApplication(); + + ExpressionFactory factory = application.getExpressionFactory(); + + ValueExpression exp = factory.createValueExpression( + context.getELContext(), "#{propertiesHandler.value}", + Object.class); + + MethodExpression listener = factory.createMethodExpression( + context.getELContext(), + "#{propertiesHandler.onPropertyChange}", Void.TYPE, + new Class[0]); + + editor.createComponent(descriptor, editorPanel, exp, listener, + "button-bar"); + + this.value = editor.getValue(descriptor, properties); + } + + setDirty(false); + } + + public void onPropertyChange() { + setDirty(true); + } + + public void onEditorModeChange() { + RenderPropertyList properties = getProperties(getCategory()); + SimpleRenderProperty property = (SimpleRenderProperty) properties + .getRenderProperty(getKey()); + + if (getUseExpression()) { + if (expression == null) { + if (property == null) { + this.expression = null; + } else { + this.expression = property.getValue(); + } + } + } else { + PropertyEditor editor = descriptor.getEditor(); + + if (editor == null) { + this.value = null; + } else { + this.value = editor.getValue(descriptor, properties); + } + } + } + + /** + * @param category + * @return + */ + protected RenderPropertyList getProperties(PropertyCategory category) { + TableRenderer renderer = viewHandler.getRenderer(); + + RenderPropertyList properties = null; + + switch (category) { + case Header: + properties = renderer.getRenderProperties().get(HEADER); + break; + case Cell: + properties = renderer.getRenderProperties().get(CELL); + break; + default: + assert false; + } + + return properties; + } + + /** + * @param event + * @return + */ + public List complete(CompleteEvent event) { + List suggestions = new LinkedList(); + + suggestions.add("context: " + event.getContext()); + suggestions.add("token: " + event.getToken()); + + return suggestions; + } + + public void apply() { + RenderPropertyList properties = getProperties(descriptor.getCategory()); + + if (getUseExpression()) { + if (expression == null) { + properties.removeRenderProperty(descriptor.getKey()); + } else { + SimpleRenderProperty property = new SimpleRenderProperty( + descriptor.getKey(), expression); + properties.setRenderProperty(property); + } + } else { + PropertyEditor editor = descriptor.getEditor(); + editor.setValue(descriptor, properties, value); + } + + setDirty(false); + + viewHandler.render(); + } + + /** + * @return the menu + */ + public PanelMenu getMenu() { + return menu; + } + + /** + * @param menu the menu to set + */ + public void setMenu(PanelMenu menu) { + List children = menu.getChildren(); + + children.clear(); + children.add(createSubMenu(PropertyCategory.Header)); + children.add(createSubMenu(PropertyCategory.Cell)); + + this.menu = menu; + } + + /** + * @param category + * @return + */ + protected UISubmenu createSubMenu(PropertyCategory category) { + String postfix = category.name().toLowerCase(); + + UISubmenu categoryMenu = new UISubmenu(); + categoryMenu.setId("menu-" + postfix); + categoryMenu.setLabel(bundle.getString("properties.category." + + category.name())); + + UISubmenu colorMenu = new UISubmenu(); + colorMenu.setId("menu-color-" + postfix); + colorMenu.setLabel(bundle.getString("properties.category.color")); + colorMenu.setIcon("ui-icon-image"); + colorMenu.getChildren().add(createMenuItem(category, "fgColor")); + colorMenu.getChildren().add(createMenuItem(category, "bgColor")); + + categoryMenu.getChildren().add(colorMenu); + + UISubmenu fontMenu = new UISubmenu(); + fontMenu.setId("menu-font-" + postfix); + fontMenu.setLabel(bundle.getString("properties.category.font")); + fontMenu.setIcon("ui-icon-pencil"); + fontMenu.getChildren().add(createMenuItem(category, "fontFamily")); + fontMenu.getChildren().add(createMenuItem(category, "fontSize")); + fontMenu.getChildren().add(createMenuItem(category, "fontStyle")); + + categoryMenu.getChildren().add(fontMenu); + + categoryMenu.getChildren().add(createMenuItem(category, "label")); + categoryMenu.getChildren().add(createMenuItem(category, "link")); + categoryMenu.getChildren().add(createMenuItem(category, "styleClass")); + + return categoryMenu; + } + + /** + * @param category + * @param key + * @return + */ + protected UIMenuItem createMenuItem(PropertyCategory category, String key) { + PropertyDescriptor property = descriptorFactory.getDescriptor(category, + key); + + FacesContext context = FacesContext.getCurrentInstance(); + + Application application = context.getApplication(); + ExpressionFactory factory = application.getExpressionFactory(); + + UIMenuItem item = new UIMenuItem(); + item.setId("mi-" + key.toLowerCase() + "-" + + category.name().toLowerCase()); + item.setValue(property.getName(context)); + item.setTitle(property.getDescription(context)); + item.setIcon(property.getIcon()); + + if (category.equals(getCategory()) && key.equals(getKey())) { + item.setStyleClass("ui-state-highlight"); + } + + MethodExpression exp = factory.createMethodExpression( + context.getELContext(), "#{propertiesHandler.selectProperty}", + Void.TYPE, new Class[0]); + item.setActionExpression(exp); + item.setUpdate("content,button-bar,:growl"); + item.setOnclick("jQuery('.ui-menuitem-link').removeClass('ui-state-highlight'); " + + "jQuery(this).addClass('ui-state-highlight');"); + item.setOncomplete("applyThemeToCMEditor('.properties-config .CodeMirror')"); + + UIParameter keyParam = new UIParameter(); + keyParam.setName("key"); + keyParam.setValue(key); + + item.getChildren().add(keyParam); + + UIParameter categoryParam = new UIParameter(); + categoryParam.setName("category"); + categoryParam.setValue(category.name()); + + item.getChildren().add(categoryParam); + + return item; + } + + /** + * @return key + */ + public String getKey() { + FacesContext context = FacesContext.getCurrentInstance(); + + Map attributes = context.getViewRoot().getAttributes(); + + return (String) attributes.get("propertyKey"); + } + + /** + * @param key + */ + public void setKey(String key) { + FacesContext context = FacesContext.getCurrentInstance(); + + Map attributes = context.getViewRoot().getAttributes(); + attributes.put("propertyKey", key); + } + + /** + * @return category + */ + public PropertyCategory getCategory() { + FacesContext context = FacesContext.getCurrentInstance(); + + Map attributes = context.getViewRoot().getAttributes(); + + return (PropertyCategory) attributes.get("propertyCategory"); + } + + /** + * @param category + */ + public void setCategory(PropertyCategory category) { + FacesContext context = FacesContext.getCurrentInstance(); + + Map attributes = context.getViewRoot().getAttributes(); + attributes.put("propertyCategory", category); + } + + /** + * @return dirty + */ + public boolean isDirty() { + FacesContext context = FacesContext.getCurrentInstance(); + + Map attributes = context.getViewRoot().getAttributes(); + + Object attribute = attributes.get("propertyChanged"); + + return attribute != null && (Boolean) attribute; + } + + /** + * @param dirty + */ + public void setDirty(boolean dirty) { + FacesContext context = FacesContext.getCurrentInstance(); + + Map attributes = context.getViewRoot().getAttributes(); + attributes.put("propertyChanged", dirty); + } + + public boolean isSet() { + boolean isSet = false; + + if (descriptor != null) { + RenderProperty property = getProperties(getCategory()) + .getRenderProperty(getKey()); + isSet = property != null; + } + + return isSet; + } + + /** + * @return the useExpression + */ + public boolean getUseExpression() { + FacesContext context = FacesContext.getCurrentInstance(); + + Map attributes = context.getViewRoot().getAttributes(); + + Object attribute = attributes.get("useExpression"); + + return attribute != null && (Boolean) attribute; + } + + /** + * @param useExpression the useExpression to set + */ + public void setUseExpression(boolean useExpression) { + FacesContext context = FacesContext.getCurrentInstance(); + + Map attributes = context.getViewRoot().getAttributes(); + attributes.put("useExpression", useExpression); + } + + public void reset() { + this.value = null; + this.expression = null; + + setDirty(true); + setUseExpression(false); + } + + /** + * @return the descriptor + */ + public PropertyDescriptor getDescriptor() { + return descriptor; + } + + /** + * @return the descriptorFactory + */ + public PropertyDescriptorFactory getDescriptorFactory() { + return descriptorFactory; + } + + /** + * @param descriptorFactory the descriptorFactory to set + */ + public void setDescriptorFactory(PropertyDescriptorFactory descriptorFactory) { + this.descriptorFactory = descriptorFactory; + } + + /** + * @return the viewHandler + */ + public ViewHandler getViewHandler() { + return viewHandler; + } + + /** + * @param viewHandler the viewHandler to set + */ + public void setViewHandler(ViewHandler viewHandler) { + this.viewHandler = viewHandler; + } + + /** + * @return the editorPanel + */ + public UIComponent getEditorPanel() { + return editorPanel; + } + + /** + * @param editorPanel the editorPanel to set + */ + public void setEditorPanel(UIComponent editorPanel) { + this.editorPanel = editorPanel; + } + + /** + * @return the value + */ + public Object getValue() { + return value; + } + + /** + * @param value the value to set + */ + public void setValue(Object value) { + this.value = value; + } + + /** + * @return the expression + */ + public String getExpression() { + return expression; + } + + /** + * @param expression the expression to set + */ + public void setExpression(String expression) { + this.expression = expression; + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/ReportOpener.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/ReportOpener.java index 326c7b65..b79f5ca3 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/ReportOpener.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/ReportOpener.java @@ -10,8 +10,10 @@ import javax.faces.bean.ManagedBean; import javax.faces.bean.ManagedProperty; import javax.faces.bean.RequestScoped; +import javax.faces.bean.ViewScoped; import javax.faces.context.FacesContext; import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; import org.apache.commons.configuration.ConfigurationException; import org.pivot4j.analytics.config.Settings; @@ -22,252 +24,275 @@ import org.pivot4j.analytics.repository.ReportRepository; import org.pivot4j.analytics.state.ViewState; import org.pivot4j.analytics.state.ViewStateHolder; +import org.pivot4j.analytics.util.DspCredor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @ManagedBean(name = "reportOpener") -@RequestScoped +@ViewScoped public class ReportOpener { - private Logger log = LoggerFactory.getLogger(getClass()); + private Logger log = LoggerFactory.getLogger(getClass()); - @ManagedProperty(value = "#{settings}") - private Settings settings; + @ManagedProperty(value = "#{settings}") + private Settings settings; - @ManagedProperty(value = "#{viewStateHolder}") - private ViewStateHolder viewStateHolder; + @ManagedProperty(value = "#{viewStateHolder}") + private ViewStateHolder viewStateHolder; - @ManagedProperty(value = "#{dataSourceManager}") - private DataSourceManager dataSourceManager; + @ManagedProperty(value = "#{dataSourceManager}") + private DataSourceManager dataSourceManager; - @ManagedProperty(value = "#{reportRepository}") - private ReportRepository reportRepository; + @ManagedProperty(value = "#{reportRepository}") + private ReportRepository reportRepository; - private String fileId; + private String fileId; - private String path; + private String path; - private boolean embeded = false; + private String credor; - public void load() throws IOException, ClassNotFoundException, - ConfigurationException, DataSourceNotFoundException { - FacesContext context = FacesContext.getCurrentInstance(); + private boolean embeded = false; - HttpServletRequest request = (HttpServletRequest) context - .getExternalContext().getRequest(); + HttpSession session = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(false); - ReportFile file = getReportFromRequest(request); + public void loadCredor() throws IOException, ClassNotFoundException, + ConfigurationException, DataSourceNotFoundException { + FacesContext context = FacesContext.getCurrentInstance(); - if (file == null) { - throw new FacesException("Unable to find requested report file."); - } + NavigationHandler navigationHandler = context.getApplication() + .getNavigationHandler(); - ViewState state = createViewWithRequest(request, file); + session = (HttpSession) context.getExternalContext().getSession(true); + session.setAttribute("idCredor", credor); + session.setAttribute("client", credor); - if (state == null) { - throw new FacesException("Unable to create a view state."); - } + String path = "index?faces-redirect=true"; - ReportContent content = reportRepository.getReportContent(file); - content.read(state, dataSourceManager, settings.getConfiguration()); + navigationHandler.handleNavigation(context, null, path); + } - viewStateHolder.registerState(state); + public void load() throws IOException, ClassNotFoundException, + ConfigurationException, DataSourceNotFoundException { + FacesContext context = FacesContext.getCurrentInstance(); - NavigationHandler navigationHandler = context.getApplication() - .getNavigationHandler(); + HttpServletRequest request = (HttpServletRequest) context + .getExternalContext().getRequest(); - String target = embeded ? "embed" : "view"; + ReportFile file = getReportFromRequest(request); - String path = String.format("%s?faces-redirect=true&%s=%s", target, - settings.getViewParameterName(), state.getId()); + if (file == null) { + throw new FacesException("Unable to find requested report file."); + } - navigationHandler.handleNavigation(context, null, path); - } + ViewState state = createViewWithRequest(request, file); - /** - * @param request - * @param file - * @return - */ - protected ViewState createViewWithRequest(HttpServletRequest request, - ReportFile file) { - String viewId = request.getParameter(settings.getViewParameterName()); + if (state == null) { + throw new FacesException("Unable to create a view state."); + } - if (log.isInfoEnabled()) { - log.info("Creating a view '{}' with a report: {}", viewId, file); - } + ReportContent content = reportRepository.getReportContent(file); + content.read(state, dataSourceManager, settings.getConfiguration()); - ViewState state; + viewStateHolder.registerState(state); - String name = file.getName(); + NavigationHandler navigationHandler = context.getApplication() + .getNavigationHandler(); - if (name.toLowerCase().endsWith(".pivot4j")) { - name = name.substring(0, name.length() - 8); - } + String target = embeded ? "embed" : "view"; + + String path = String.format("%s?faces-redirect=true&%s=%s", target, + settings.getViewParameterName(), state.getId()); + + navigationHandler.handleNavigation(context, null, path); + } + + /** + * @param request + * @param file + * @return + */ + protected ViewState createViewWithRequest(HttpServletRequest request, + ReportFile file) { + String viewId = request.getParameter(settings.getViewParameterName()); + + if (log.isInfoEnabled()) { + log.info("Creating a view '{}' with a report: {}", viewId, file); + } + + ViewState state; + + String name = file.getName(); + + if (name.toLowerCase().endsWith(".pivot4j")) { + name = name.substring(0, name.length() - 8); + } + + if (viewId == null) { + state = viewStateHolder.createNewState(); + state.setName(name); + } else { + state = new ViewState(viewId, name); + } + + @SuppressWarnings("unchecked") + Map parameterMap = request.getParameterMap(); + + Map parameters = new HashMap( + parameterMap.size()); + + for (String key : parameterMap.keySet()) { + String[] values = parameterMap.get(key); + + if (values == null) { + continue; + } + + if (values.length == 1) { + parameters.put(key, values[0]); + } else { + parameters.put(key, Arrays.asList(values)); + } + } + + state.setFile(file); + state.setParameters(parameters); + state.setReadOnly(!file.canWrite()); + state.setEditable(!state.isReadOnly() && !embeded); + + return state; + } + + /** + * @param request + * @return + * @throws IOException + */ + protected ReportFile getReportFromRequest(HttpServletRequest request) + throws IOException { + ReportFile file = null; + + if (fileId != null) { + if (log.isDebugEnabled()) { + log.debug("Opening report file with id: {}", fileId); + } + + file = reportRepository.getFileById(fileId); + } else if (path != null) { + if (log.isDebugEnabled()) { + log.debug("Opening report file with path: {}", path); + } + + file = reportRepository.getFile(path); + } + + return file; + } + + /** + * @return the fileId + */ + public String getFileId() { + return fileId; + } + + /** + * @param fileId the fileId to set + */ + public void setFileId(String fileId) { + this.fileId = fileId; + } + + /** + * @return the path + */ + public String getPath() { + return path; + } + + /** + * @param path the path to set + */ + public void setPath(String path) { + this.path = path; + } + + /** + * @return the embeded + */ + public boolean isEmbeded() { + return embeded; + } + + /** + * @param embeded the embeded to set + */ + public void setEmbeded(boolean embeded) { + this.embeded = embeded; + } + + /** + * @return the settings + */ + public Settings getSettings() { + return settings; + } + + /** + * @param settings the settings to set + */ + public void setSettings(Settings settings) { + this.settings = settings; + } + + /** + * @return the viewStateHolder + */ + public ViewStateHolder getViewStateHolder() { + return viewStateHolder; + } + + /** + * @param viewStateHolder the viewStateHolder to set + */ + public void setViewStateHolder(ViewStateHolder viewStateHolder) { + this.viewStateHolder = viewStateHolder; + } + + /** + * @return the dataSourceManager + */ + public DataSourceManager getDataSourceManager() { + return dataSourceManager; + } + + /** + * @param dataSourceManager the dataSourceManager to set + */ + public void setDataSourceManager(DataSourceManager dataSourceManager) { + this.dataSourceManager = dataSourceManager; + } + + /** + * @return the reportRepository + */ + public ReportRepository getReportRepository() { + return reportRepository; + } + + /** + * @param reportRepository the reportRepository to set + */ + public void setReportRepository(ReportRepository reportRepository) { + this.reportRepository = reportRepository; + } + + public String getCredor() { + return credor; + } + + public void setCredor(String credor) { + this.credor = credor; + } - if (viewId == null) { - state = viewStateHolder.createNewState(); - state.setName(name); - } else { - state = new ViewState(viewId, name); - } - - @SuppressWarnings("unchecked") - Map parameterMap = request.getParameterMap(); - - Map parameters = new HashMap( - parameterMap.size()); - - for (String key : parameterMap.keySet()) { - String[] values = parameterMap.get(key); - - if (values == null) { - continue; - } - - if (values.length == 1) { - parameters.put(key, values[0]); - } else { - parameters.put(key, Arrays.asList(values)); - } - } - - state.setFile(file); - state.setParameters(parameters); - state.setReadOnly(!file.canWrite()); - state.setEditable(!state.isReadOnly() && !embeded); - - return state; - } - - /** - * @param request - * @return - * @throws IOException - */ - protected ReportFile getReportFromRequest(HttpServletRequest request) - throws IOException { - ReportFile file = null; - - if (fileId != null) { - if (log.isDebugEnabled()) { - log.debug("Opening report file with id: {}", fileId); - } - - file = reportRepository.getFileById(fileId); - } else if (path != null) { - if (log.isDebugEnabled()) { - log.debug("Opening report file with path: {}", path); - } - - file = reportRepository.getFile(path); - } - - return file; - } - - /** - * @return the fileId - */ - public String getFileId() { - return fileId; - } - - /** - * @param fileId - * the fileId to set - */ - public void setFileId(String fileId) { - this.fileId = fileId; - } - - /** - * @return the path - */ - public String getPath() { - return path; - } - - /** - * @param path - * the path to set - */ - public void setPath(String path) { - this.path = path; - } - - /** - * @return the embeded - */ - public boolean isEmbeded() { - return embeded; - } - - /** - * @param embeded - * the embeded to set - */ - public void setEmbeded(boolean embeded) { - this.embeded = embeded; - } - - /** - * @return the settings - */ - public Settings getSettings() { - return settings; - } - - /** - * @param settings - * the settings to set - */ - public void setSettings(Settings settings) { - this.settings = settings; - } - - /** - * @return the viewStateHolder - */ - public ViewStateHolder getViewStateHolder() { - return viewStateHolder; - } - - /** - * @param viewStateHolder - * the viewStateHolder to set - */ - public void setViewStateHolder(ViewStateHolder viewStateHolder) { - this.viewStateHolder = viewStateHolder; - } - - /** - * @return the dataSourceManager - */ - public DataSourceManager getDataSourceManager() { - return dataSourceManager; - } - - /** - * @param dataSourceManager - * the dataSourceManager to set - */ - public void setDataSourceManager(DataSourceManager dataSourceManager) { - this.dataSourceManager = dataSourceManager; - } - - /** - * @return the reportRepository - */ - public ReportRepository getReportRepository() { - return reportRepository; - } - - /** - * @param reportRepository - * the reportRepository to set - */ - public void setReportRepository(ReportRepository reportRepository) { - this.reportRepository = reportRepository; - } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/RepositoryHandler.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/RepositoryHandler.java index 1eac699a..19025d62 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/RepositoryHandler.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/RepositoryHandler.java @@ -20,7 +20,7 @@ import javax.faces.application.FacesMessage; import javax.faces.bean.ManagedBean; import javax.faces.bean.ManagedProperty; -import javax.faces.bean.SessionScoped; +import javax.faces.bean.ViewScoped; import javax.faces.context.FacesContext; import org.apache.commons.configuration.ConfigurationException; @@ -39,1066 +39,1064 @@ import org.pivot4j.analytics.state.ViewStateHolder; import org.pivot4j.analytics.state.ViewStateListener; import org.pivot4j.analytics.ui.navigator.RepositoryNode; -import org.primefaces.context.RequestContext; +import org.primefaces.PrimeFaces; import org.primefaces.json.JSONObject; import org.primefaces.model.TreeNode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @ManagedBean(name = "repositoryHandler") -@SessionScoped +@ViewScoped public class RepositoryHandler implements ViewStateListener, Serializable { - private static final long serialVersionUID = -860723075484210684L; + private static final long serialVersionUID = -860723075484210684L; - private Logger log = LoggerFactory.getLogger(getClass()); + private Logger log = LoggerFactory.getLogger(getClass()); - @ManagedProperty(value = "#{settings}") - private Settings settings; + @ManagedProperty(value = "#{settings}") + private Settings settings; - @ManagedProperty(value = "#{dataSourceManager}") - private DataSourceManager dataSourceManager; + @ManagedProperty(value = "#{dataSourceManager}") + private DataSourceManager dataSourceManager; - @ManagedProperty(value = "#{reportRepository}") - private ReportRepository repository; + @ManagedProperty(value = "#{reportRepository}") + private ReportRepository repository; - @ManagedProperty(value = "#{viewStateHolder}") - private ViewStateHolder viewStateHolder; + @ManagedProperty(value = "#{viewStateHolder}") + private ViewStateHolder viewStateHolder; - private TreeNode rootNode; + private TreeNode rootNode; - private TreeNode selection; + private TreeNode selection; - private String activeViewId; + private String activeViewId; - private String reportName; + private String reportName; - private String folderName; + private String folderName; - @PostConstruct - protected void initialize() { - viewStateHolder.addViewStateListener(this); + @PostConstruct + protected void initialize() { - ViewState state = viewStateHolder.createNewState(); + viewStateHolder.addViewStateListener(this); - if (state != null) { - viewStateHolder.registerState(state); + ViewState state = viewStateHolder.createNewState(); - this.activeViewId = state.getId(); - } - } + if (state != null) { + viewStateHolder.registerState(state); - @PreDestroy - protected void destroy() { - viewStateHolder.removeViewStateListener(this); - } + this.activeViewId = state.getId(); + } + } - /** - * @return the repository - */ - public ReportRepository getRepository() { - return repository; - } + @PreDestroy + protected void destroy() { + viewStateHolder.removeViewStateListener(this); + } - /** - * @param repository - * the repository to set - */ - public void setRepository(ReportRepository repository) { - this.repository = repository; - } + /** + * @return the repository + */ + public ReportRepository getRepository() { + return repository; + } - public void loadReports() { - RequestContext context = RequestContext.getCurrentInstance(); + /** + * @param repository the repository to set + */ + public void setRepository(ReportRepository repository) { + this.repository = repository; + } - List states = viewStateHolder.getStates(); + public void loadReports() { + List states = viewStateHolder.getStates(); - for (ViewState state : states) { - context.addCallbackParam(state.getId(), new JSONObject(new ViewInfo(state))); - } - } + for (ViewState state : states) { + PrimeFaces.current().ajax().addCallbackParam(state.getId(), new JSONObject(new ViewInfo(state))); + } + } - public void create() { - ViewState state = viewStateHolder.createNewState(); - viewStateHolder.registerState(state); + public void create() { + ViewState state = viewStateHolder.createNewState(); + viewStateHolder.registerState(state); - this.activeViewId = state.getId(); + this.activeViewId = state.getId(); - if (log.isInfoEnabled()) { - log.info("Created a new view state : {}", state.getId()); - } + if (log.isInfoEnabled()) { + log.info("Created a new view state : {}", state.getId()); + } - RequestContext requestContext = RequestContext.getCurrentInstance(); - requestContext.addCallbackParam("report", new JSONObject(new ViewInfo(state))); - } + PrimeFaces.current().ajax().addCallbackParam("report", new JSONObject(new ViewInfo(state))); + } - public void createDirectory() { - FacesContext context = FacesContext.getCurrentInstance(); - ResourceBundle bundle = context.getApplication().getResourceBundle( - context, "msg"); + public void createDirectory() { + FacesContext context = FacesContext.getCurrentInstance(); + ResourceBundle bundle = context.getApplication().getResourceBundle( + context, "msg"); - ReportFile parent = getTargetDirectory(); + ReportFile parent = getTargetDirectory(); - ReportFile newFile; + ReportFile newFile; - StringBuilder builder = new StringBuilder(); - builder.append(parent.getPath()); + StringBuilder builder = new StringBuilder(); + builder.append(parent.getPath()); - if (!parent.getPath().endsWith(ReportFile.SEPARATOR)) { - builder.append(ReportFile.SEPARATOR); - } + if (!parent.getPath().endsWith(ReportFile.SEPARATOR)) { + builder.append(ReportFile.SEPARATOR); + } - builder.append(folderName); + builder.append(folderName); - String path = builder.toString(); + String path = builder.toString(); - if (log.isInfoEnabled()) { - log.info("Creating a new folder : {}", path); - } + if (log.isInfoEnabled()) { + log.info("Creating a new folder : {}", path); + } - try { - if (repository.exists(path)) { - this.folderName = null; + try { + if (repository.exists(path)) { + this.folderName = null; - String title = bundle.getString("error.create.folder.title"); - String message = bundle.getString("warn.folder.exists"); + String title = bundle.getString("error.create.folder.title"); + String message = bundle.getString("warn.folder.exists"); - context.addMessage("new-folder-form:name", new FacesMessage( - FacesMessage.SEVERITY_ERROR, title, message)); + context.addMessage("new-folder-form:name", new FacesMessage( + FacesMessage.SEVERITY_ERROR, title, message)); - return; - } + return; + } - newFile = repository.createDirectory(parent, folderName); - } catch (IOException e) { - String title = bundle.getString("error.create.folder.title"); - String message = bundle.getString("error.create.folder.io") + e; + newFile = repository.createDirectory(parent, folderName); + } catch (IOException e) { + String title = bundle.getString("error.create.folder.title"); + String message = bundle.getString("error.create.folder.io") + e; - context.addMessage(null, new FacesMessage( - FacesMessage.SEVERITY_ERROR, title, message)); + context.addMessage(null, new FacesMessage( + FacesMessage.SEVERITY_ERROR, title, message)); - if (log.isErrorEnabled()) { - log.error(title, e); - } + if (log.isErrorEnabled()) { + log.error(title, e); + } - return; - } + return; + } - RepositoryNode parentNode = getRepositoryRootNode().findNode(parent); - parentNode.setExpanded(true); - parentNode.setSelected(false); - parentNode.refresh(); + RepositoryNode parentNode = getRepositoryRootNode().findNode(parent); + parentNode.setExpanded(true); + parentNode.setSelected(false); + parentNode.refresh(); - RepositoryNode newFileNode = getRepositoryRootNode().findNode(newFile); - newFileNode.setSelected(true); + RepositoryNode newFileNode = getRepositoryRootNode().findNode(newFile); + newFileNode.setSelected(true); - this.selection = newFileNode; - this.folderName = null; + this.selection = newFileNode; + this.folderName = null; - RequestContext requestContext = RequestContext.getCurrentInstance(); - requestContext.execute("PF('newFolderDialog').hide()"); - } + PrimeFaces.current().executeScript("PF('newFolderDialog').hide()"); + } - public void save() { - FacesContext context = FacesContext.getCurrentInstance(); - RequestContext requestContext = RequestContext.getCurrentInstance(); + public void save() { + FacesContext context = FacesContext.getCurrentInstance(); - ResourceBundle bundle = context.getApplication().getResourceBundle( - context, "msg"); + ResourceBundle bundle = context.getApplication().getResourceBundle( + context, "msg"); - Map parameters = context.getExternalContext() - .getRequestParameterMap(); - String param = parameters.get("close"); + Map parameters = context.getExternalContext() + .getRequestParameterMap(); + String param = parameters.get("close"); - String viewId = parameters.get("viewId"); + String viewId = parameters.get("viewId"); - if (viewId == null) { - viewId = activeViewId; - } + if (viewId == null) { + viewId = activeViewId; + } - boolean saveAndClose = "true".equals(param); + boolean saveAndClose = "true".equals(param); - ViewState state = viewStateHolder.getState(viewId); + ViewState state = viewStateHolder.getState(viewId); - ReportFile file = state.getFile(); + ReportFile file = state.getFile(); - if (file == null) { - suggestNewName(); + if (file == null) { + suggestNewName(); - requestContext.update("new-form"); - requestContext.execute("PF('newReportDialog').show()"); + PrimeFaces.current().ajax().update("new-form"); + PrimeFaces.current().executeScript("PF('newReportDialog').show()"); - return; - } + return; + } - requestContext.update(Arrays.asList(new String[] { - "toolbar-form:toolbar", "repository-form:repository-panel", - "growl" })); + PrimeFaces.current().ajax().update(Arrays.asList(new String[]{ + "toolbar-form:toolbar", "repository-form:repository-panel", + "growl"})); - try { - repository.setReportContent(file, new ReportContent(state)); - } catch (ConfigurationException e) { - String title = bundle.getString("error.save.report.title"); - String message = bundle.getString("error.save.report.format") + e; + try { + repository.setReportContent(file, new ReportContent(state)); + } catch (ConfigurationException e) { + String title = bundle.getString("error.save.report.title"); + String message = bundle.getString("error.save.report.format") + e; - context.addMessage(null, new FacesMessage( - FacesMessage.SEVERITY_INFO, title, message)); + context.addMessage(null, new FacesMessage( + FacesMessage.SEVERITY_INFO, title, message)); - if (log.isErrorEnabled()) { - log.error(title, e); - } + if (log.isErrorEnabled()) { + log.error(title, e); + } - return; - } catch (IOException e) { - String title = bundle.getString("error.save.report.title"); - String message = bundle.getString("error.save.report.io") + e; + return; + } catch (IOException e) { + String title = bundle.getString("error.save.report.title"); + String message = bundle.getString("error.save.report.io") + e; - context.addMessage(null, new FacesMessage( - FacesMessage.SEVERITY_ERROR, title, message)); + context.addMessage(null, new FacesMessage( + FacesMessage.SEVERITY_ERROR, title, message)); - if (log.isErrorEnabled()) { - log.error(title, e); - } + if (log.isErrorEnabled()) { + log.error(title, e); + } - return; - } + return; + } - if (saveAndClose) { - requestContext.update("close-form"); + if (saveAndClose) { + PrimeFaces.current().ajax().update("close-form"); - close(viewId); - } else { - if (this.selection != null) { - this.selection.setSelected(false); - } + close(viewId); + } else { + if (this.selection != null) { + this.selection.setSelected(false); + } - RepositoryNode node = getRepositoryRootNode().selectNode(file); - node.setViewId(state.getId()); - node.setSelected(true); + RepositoryNode node = getRepositoryRootNode().selectNode(file); + node.setViewId(state.getId()); + node.setSelected(true); - this.selection = node; - } + this.selection = node; + } - state.setDirty(false); + state.setDirty(false); - String title = bundle.getString("message.save.report.title"); - String message = bundle.getString("message.save.report.message"); + String title = bundle.getString("message.save.report.title"); + String message = bundle.getString("message.save.report.message"); - context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, - title, message)); + context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, + title, message)); - requestContext.execute("enableSave(false);"); - } + PrimeFaces.current().executeScript("enableSave(false);"); + } - public void saveAs() { - FacesContext context = FacesContext.getCurrentInstance(); - ResourceBundle bundle = context.getApplication().getResourceBundle( - context, "msg"); + public void saveAs() { + FacesContext context = FacesContext.getCurrentInstance(); + ResourceBundle bundle = context.getApplication().getResourceBundle( + context, "msg"); - ReportFile parent = getTargetDirectory(); + ReportFile parent = getTargetDirectory(); - RepositoryNode root = getRepositoryRootNode(); + RepositoryNode root = getRepositoryRootNode(); - ViewState state = viewStateHolder.getState(activeViewId); + ViewState state = viewStateHolder.getState(activeViewId); - if (state.getFile() != null) { - RepositoryNode node = root.findNode(state.getFile()); - if (node != null) { - node.setViewId(null); - } - } + if (state.getFile() != null) { + RepositoryNode node = root.findNode(state.getFile()); + if (node != null) { + node.setViewId(null); + } + } - ReportContent content = new ReportContent(state); + ReportContent content = new ReportContent(state); - if (reportName.toLowerCase().endsWith(".pivot4j")) { - reportName = reportName.substring(0, reportName.length() - 8); - } + String extension = settings.getExtension(); - String fileName = reportName + ".pivot4j"; + if (reportName.toLowerCase().endsWith(extension)) { + reportName = reportName.substring(0, reportName.length() - (extension.length() + 1)); + } - ReportFile file; + String fileName = reportName + '.' + extension; - try { - file = repository.createFile(parent, fileName, content); - } catch (ConfigurationException e) { - String title = bundle.getString("error.save.report.title"); - String message = bundle.getString("error.save.report.format") + e; + ReportFile file; - context.addMessage(null, new FacesMessage( - FacesMessage.SEVERITY_ERROR, title, message)); + try { + file = repository.createFile(parent, fileName, content); + } catch (ConfigurationException e) { + String title = bundle.getString("error.save.report.title"); + String message = bundle.getString("error.save.report.format") + e; - if (log.isErrorEnabled()) { - log.error(title, e); - } + context.addMessage(null, new FacesMessage( + FacesMessage.SEVERITY_ERROR, title, message)); - return; - } catch (IOException e) { - String title = bundle.getString("error.save.report.title"); - String message = bundle.getString("error.save.report.io") + e; + if (log.isErrorEnabled()) { + log.error(title, e); + } - context.addMessage(null, new FacesMessage( - FacesMessage.SEVERITY_ERROR, title, message)); + return; + } catch (IOException e) { + String title = bundle.getString("error.save.report.title"); + String message = bundle.getString("error.save.report.io") + e; - if (log.isErrorEnabled()) { - log.error(title, e); - } + context.addMessage(null, new FacesMessage( + FacesMessage.SEVERITY_ERROR, title, message)); - return; - } + if (log.isErrorEnabled()) { + log.error(title, e); + } - state.setName(reportName); - state.setFile(file); - state.setDirty(false); + return; + } - RepositoryNode parentNode = root.findNode(parent); - parentNode.setSelected(false); - parentNode.setExpanded(true); + state.setName(reportName); + state.setFile(file); + state.setDirty(false); - if (this.selection != null) { - this.selection.setSelected(false); - } + RepositoryNode parentNode = root.findNode(parent); + parentNode.setSelected(false); + parentNode.setExpanded(true); - RepositoryNode node = parentNode.selectNode(file); - if (node == null) { - node = new RepositoryNode(file, repository); - node.setParent(parentNode); + if (this.selection != null) { + this.selection.setSelected(false); + } - parentNode.getChildren().add(node); + RepositoryNode node = parentNode.selectNode(file); + if (node == null) { + node = new RepositoryNode(file, repository); + node.setParent(parentNode); - final RepositoryFileComparator comparator = new RepositoryFileComparator(); + parentNode.getChildren().add(node); - Collections.sort(parentNode.getChildren(), - new Comparator() { + final RepositoryFileComparator comparator = new RepositoryFileComparator(); - @Override - public int compare(TreeNode t1, TreeNode t2) { - RepositoryNode r1 = (RepositoryNode) t1; - RepositoryNode r2 = (RepositoryNode) t2; + Collections.sort(parentNode.getChildren(), + new Comparator() { - return comparator.compare(r1.getObject(), - r2.getObject()); - } - }); - } + @Override + public int compare(TreeNode t1, TreeNode t2) { + RepositoryNode r1 = (RepositoryNode) t1; + RepositoryNode r2 = (RepositoryNode) t2; - node.setViewId(activeViewId); - node.setSelected(true); + return comparator.compare(r1.getObject(), + r2.getObject()); + } + }); + } - this.selection = node; - this.reportName = null; + node.setViewId(activeViewId); + node.setSelected(true); - RequestContext requestContext = RequestContext.getCurrentInstance(); - requestContext.addCallbackParam("name", state.getName()); - requestContext.addCallbackParam("path", file.getPath()); + this.selection = node; + this.reportName = null; - String title = bundle.getString("message.save.report.title"); - String message = bundle.getString("message.saveAs.report.message") - + file.getPath(); + PrimeFaces.current().ajax().addCallbackParam("name", state.getName()); + PrimeFaces.current().ajax().addCallbackParam("path", file.getPath()); - context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, - title, message)); - } + String title = bundle.getString("message.save.report.title"); + String message = bundle.getString("message.saveAs.report.message") + + file.getPath(); - public void open() { - if (selection == null) { - if (log.isWarnEnabled()) { - log.warn("Unable to load report from empty or multiple selection."); - } + context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, + title, message)); + } - return; - } + public void open() { + if (selection == null) { + if (log.isWarnEnabled()) { + log.warn("Unable to load report from empty or multiple selection."); + } - FacesContext context = FacesContext.getCurrentInstance(); - ResourceBundle bundle = context.getApplication().getResourceBundle( - context, "msg"); + return; + } - RepositoryNode node = (RepositoryNode) selection; - ReportFile file = node.getObject(); + FacesContext context = FacesContext.getCurrentInstance(); + ResourceBundle bundle = context.getApplication().getResourceBundle( + context, "msg"); - String viewId = UUID.randomUUID().toString(); + RepositoryNode node = (RepositoryNode) selection; + ReportFile file = node.getObject(); - String name = file.getName(); + String viewId = UUID.randomUUID().toString(); - if (name.toLowerCase().endsWith(".pivot4j")) { - name = name.substring(0, name.length() - 8); - } + String name = file.getName(); - ViewState state = new ViewState(viewId, name); - state.setFile(file); + String extension = settings.getExtension(); - String errorMessage = null; - Exception exception = null; + if (name.toLowerCase().endsWith(extension)) { + name = name.substring(0, name.length() - (extension.length() + 1)); + } - try { - ReportContent content = repository.getReportContent(file); - content.read(state, dataSourceManager, settings.getConfiguration()); - } catch (ConfigurationException e) { - exception = e; - errorMessage = bundle.getString("error.open.report.format") + e; - } catch (DataSourceNotFoundException e) { - exception = e; - errorMessage = bundle.getString("error.open.report.dataSource") - + e.getConnectionInfo().getCatalogName(); - } catch (IOException e) { - exception = e; - errorMessage = bundle.getString("error.open.report.io") + e; - } + ViewState state = new ViewState(viewId, name); + state.setFile(file); - if (exception != null) { - String title = bundle.getString("error.open.report.title"); + String errorMessage = null; + Exception exception = null; - context.addMessage(null, new FacesMessage( - FacesMessage.SEVERITY_ERROR, title, errorMessage)); + try { + ReportContent content = repository.getReportContent(file); + content.read(state, dataSourceManager, settings.getConfiguration()); + } catch (ConfigurationException e) { + exception = e; + errorMessage = bundle.getString("error.open.report.format") + e; + } catch (DataSourceNotFoundException e) { + exception = e; + errorMessage = bundle.getString("error.open.report.dataSource") + + e.getConnectionInfo().getCatalogName(); + } catch (IOException e) { + exception = e; + errorMessage = bundle.getString("error.open.report.io") + e; + } - if (log.isErrorEnabled()) { - log.error(title, exception); - } + if (exception != null) { + String title = bundle.getString("error.open.report.title"); - return; - } + context.addMessage(null, new FacesMessage( + FacesMessage.SEVERITY_ERROR, title, errorMessage)); - viewStateHolder.registerState(state); + if (log.isErrorEnabled()) { + log.error(title, exception); + } - if (log.isInfoEnabled()) { - log.info("Created a new view state : {}", viewId); - } + return; + } - this.activeViewId = viewId; + viewStateHolder.registerState(state); - RequestContext requestContext = RequestContext.getCurrentInstance(); - requestContext.addCallbackParam("report", new JSONObject(new ViewInfo(state))); - } + if (log.isInfoEnabled()) { + log.info("Created a new view state : {}", viewId); + } - public void refresh() { - RepositoryNode node = (RepositoryNode) selection; - node.refresh(); - } + this.activeViewId = viewId; - public void delete() { - ViewState state = getActiveView(); - ReportFile file = state.getFile(); + PrimeFaces.current().ajax().addCallbackParam("report", new JSONObject(new ViewInfo(state))); + } - delete(state); + public void refresh() { + RepositoryNode node = (RepositoryNode) selection; + node.refresh(); + } - if (file != null) { - delete(file); - } + public void delete() { + ViewState state = getActiveView(); + ReportFile file = state.getFile(); - FacesContext context = FacesContext.getCurrentInstance(); - ResourceBundle bundle = context.getApplication().getResourceBundle( - context, "msg"); + delete(state); - String title = bundle.getString("message.delete.report.title"); - String message = bundle.getString("message.delete.report.message"); + if (file != null) { + delete(file); + } - context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, - title, message)); - } + FacesContext context = FacesContext.getCurrentInstance(); + ResourceBundle bundle = context.getApplication().getResourceBundle( + context, "msg"); - public void deleteFile() { - RepositoryNode node = (RepositoryNode) selection; + String title = bundle.getString("message.delete.report.title"); + String message = bundle.getString("message.delete.report.message"); - if (node.getViewId() != null) { - delete(viewStateHolder.getState(node.getViewId())); - } + context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, + title, message)); + } - delete(node.getObject()); + public void deleteFile() { + RepositoryNode node = (RepositoryNode) selection; - FacesContext context = FacesContext.getCurrentInstance(); - ResourceBundle bundle = context.getApplication().getResourceBundle( - context, "msg"); + if (node.getViewId() != null) { + delete(viewStateHolder.getState(node.getViewId())); + } - String title = bundle.getString("message.delete.report.title"); - String message = bundle.getString("message.delete.report.message"); + delete(node.getObject()); - context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, - title, message)); - } + FacesContext context = FacesContext.getCurrentInstance(); + ResourceBundle bundle = context.getApplication().getResourceBundle( + context, "msg"); - public void deleteDirectory() { - FacesContext context = FacesContext.getCurrentInstance(); - ResourceBundle bundle = context.getApplication().getResourceBundle( - context, "msg"); + String title = bundle.getString("message.delete.report.title"); + String message = bundle.getString("message.delete.report.message"); - RepositoryNode node = (RepositoryNode) selection; - ReportFile directory = node.getObject(); + context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, + title, message)); + } - try { - List states = viewStateHolder.getStates(); + public void deleteDirectory() { + FacesContext context = FacesContext.getCurrentInstance(); + ResourceBundle bundle = context.getApplication().getResourceBundle( + context, "msg"); - for (ViewState state : states) { - if (state.getFile() == null) { - continue; - } + RepositoryNode node = (RepositoryNode) selection; + ReportFile directory = node.getObject(); - ReportFile file = state.getFile(); + try { + List states = viewStateHolder.getStates(); - List ancestors = file.getAncestors(); + for (ViewState state : states) { + if (state.getFile() == null) { + continue; + } - if (ancestors.contains(directory)) { - String title = bundle.getString("warn.folder.delete.title"); - String message = bundle - .getString("warn.folder.delete.openReport.message"); + ReportFile file = state.getFile(); - context.addMessage(null, new FacesMessage( - FacesMessage.SEVERITY_WARN, title, message)); + List ancestors = file.getAncestors(); - return; - } - } + if (ancestors.contains(directory)) { + String title = bundle.getString("warn.folder.delete.title"); + String message = bundle + .getString("warn.folder.delete.openReport.message"); - repository.deleteFile(directory); + context.addMessage(null, new FacesMessage( + FacesMessage.SEVERITY_WARN, title, message)); - selection.getParent().getChildren().remove(selection); + return; + } + } - this.selection = null; + repository.deleteFile(directory); - String title = bundle.getString("message.delete.folder.title"); - String message = bundle.getString("message.delete.folder.message"); + selection.getParent().getChildren().remove(selection); - context.addMessage(null, new FacesMessage( - FacesMessage.SEVERITY_INFO, title, message)); - } catch (IOException e) { - String title = bundle.getString("error.delete.folder.title"); - String message = bundle.getString("error.delete.folder.message") - + e; + this.selection = null; - context.addMessage(null, new FacesMessage( - FacesMessage.SEVERITY_ERROR, title, message)); + String title = bundle.getString("message.delete.folder.title"); + String message = bundle.getString("message.delete.folder.message"); - if (log.isErrorEnabled()) { - log.error(title, e); - } - } - } + context.addMessage(null, new FacesMessage( + FacesMessage.SEVERITY_INFO, title, message)); + } catch (IOException e) { + String title = bundle.getString("error.delete.folder.title"); + String message = bundle.getString("error.delete.folder.message") + + e; - /** - * @param state - */ - protected void delete(ViewState state) { - String viewId = state.getId(); + context.addMessage(null, new FacesMessage( + FacesMessage.SEVERITY_ERROR, title, message)); - viewStateHolder.unregisterState(viewId); + if (log.isErrorEnabled()) { + log.error(title, e); + } + } + } - if (viewId.equals(activeViewId)) { - this.activeViewId = null; + /** + * @param state + */ + protected void delete(ViewState state) { + String viewId = state.getId(); - synchronized (viewStateHolder) { - List states = viewStateHolder.getStates(); - - int index = states.indexOf(state); - if (index >= states.size() - 1) { - index--; - } else { - index++; - } - - if (index > -1 && index < states.size()) { - this.activeViewId = states.get(index).getId(); - } - } - } - - RequestContext.getCurrentInstance().execute( - String.format("closeTab(getTabIndex('%s'))", viewId)); - } - - /** - * @param file - */ - protected void delete(ReportFile file) { - try { - repository.deleteFile(file); - } catch (IOException e) { - FacesContext context = FacesContext.getCurrentInstance(); - ResourceBundle bundle = context.getApplication().getResourceBundle( - context, "msg"); + viewStateHolder.unregisterState(viewId); - String title = bundle.getString("error.delete.report.title"); - String message = bundle.getString("error.delete.report.message") - + e; - - context.addMessage(null, new FacesMessage( - FacesMessage.SEVERITY_ERROR, title, message)); - - if (log.isErrorEnabled()) { - log.error(title, e); - } - - return; - } - - if (selection instanceof RepositoryNode) { - RepositoryNode node = (RepositoryNode) selection; - if (node.getObject().equals(file)) { - selection.getParent().getChildren().remove(selection); - - this.selection = null; - } - } - } - - public void close() { - FacesContext context = FacesContext.getCurrentInstance(); - - Map parameters = context.getExternalContext() - .getRequestParameterMap(); - String viewId = parameters.get("viewId"); - - close(viewId); - } - - /** - * @param viewId - */ - public void close(String viewId) { - String viewToClose; - - if (viewId == null) { - viewToClose = this.activeViewId; - this.activeViewId = null; - } else { - viewToClose = viewId; - } - - ViewState view = viewStateHolder.getState(viewToClose); - int index = viewStateHolder.getStates().indexOf(view); - - viewStateHolder.unregisterState(viewToClose); - - RequestContext.getCurrentInstance().execute( - String.format("closeTab(%s)", index)); - } - - public boolean isOpenEnabled() { - if (selection != null) { - RepositoryNode node = (RepositoryNode) selection; - ReportFile file = node.getObject(); - - if (!file.isDirectory()) { - List states = viewStateHolder.getStates(); - for (ViewState state : states) { - if (file.equals(state.getFile())) { - return false; - } - } - - return true; - } - } - - return false; - } - - public boolean isDeleteEnabled() { - if (selection != null) { - RepositoryNode node = (RepositoryNode) selection; - ReportFile file = node.getObject(); - - return !file.isRoot(); - } - - return false; - } - - public void onTabChange() { - FacesContext context = FacesContext.getCurrentInstance(); - - Map parameters = context.getExternalContext() - .getRequestParameterMap(); - - select(parameters.get("viewId")); - } + if (viewId.equals(activeViewId)) { + this.activeViewId = null; - public void onSelectionChange() { - RepositoryNode root = getRepositoryRootNode(); - root.clearSelection(); + synchronized (viewStateHolder) { + List states = viewStateHolder.getStates(); - if (selection != null) { - selection.setSelected(true); - } - } - - /** - * @param viewId - */ - protected void select(String viewId) { - this.activeViewId = viewId; - - ViewState state = viewStateHolder.getState(activeViewId); - - RepositoryNode root = getRepositoryRootNode(); - root.clearSelection(); - - if (state != null && state.getFile() != null) { - this.selection = root.selectNode(state.getFile()); - } - } - - public void onChange() { - ViewState state = getActiveView(); - if (state != null) { - state.setDirty(true); - } - } - - public void suggestNewName() { - String name = null; - - ViewState state = getActiveView(); - if (state != null) { - name = state.getName(); - } - - if (name == null) { - this.reportName = null; - return; - } - - if (name.toLowerCase().endsWith(".pivot4j")) { - name = name.substring(0, name.length() - 8); - } - - ReportFile parent = getTargetDirectory(); + int index = states.indexOf(state); + if (index >= states.size() - 1) { + index--; + } else { + index++; + } + + if (index > -1 && index < states.size()) { + this.activeViewId = states.get(index).getId(); + } + } + } + + PrimeFaces.current().executeScript( + String.format("closeTab(getTabIndex('%s'))", viewId)); + } - Set names; - - try { - List children = repository.getFiles(parent); - - names = new HashSet(children.size()); - - for (ReportFile child : children) { - String childName = child.getName(); - - if (childName.toLowerCase().endsWith(".pivot4j")) { - childName = childName.substring(0, childName.length() - 8); - } - - names.add(childName); - } - } catch (IOException e) { - throw new FacesException(e); - } - - Pattern pattern = Pattern.compile("([^\\(]+)\\(([0-9]+)\\)"); - - while (names.contains(name)) { - Matcher matcher = pattern.matcher(name); - - if (matcher.matches()) { - String prefix = matcher.group(1); - int suffix = Integer.parseInt(matcher.group(2)) + 1; - - StringBuilder builder = new StringBuilder(); - builder.append(prefix); - builder.append("("); - builder.append(Integer.toString(suffix)); - builder.append(")"); - - name = builder.toString(); - } else { - name += "(2)"; - } - } - - this.reportName = name; - } - - protected ReportFile getTargetDirectory() { - ReportFile parent = null; - - if (selection != null) { - RepositoryNode node = (RepositoryNode) selection; - - ReportFile selectedFile = node.getObject(); - if (selectedFile.isDirectory()) { - parent = selectedFile; - } else { - try { - parent = selectedFile.getParent(); - } catch (IOException e) { - throw new FacesException(e); - } - } - } - - if (parent == null) { - try { - parent = repository.getRoot(); - } catch (IOException e) { - throw new FacesException(e); - } - } - - return parent; - } - - /** - * @return the rootNode - */ - public TreeNode getRootNode() { - if (rootNode == null) { - this.rootNode = new DefaultTreeNode(); - - rootNode.setExpanded(true); - - RepositoryNode node; - - try { - node = new RepositoryNode(repository.getRoot(), repository); - } catch (IOException e) { - throw new FacesException(e); - } - - node.setExpanded(true); - node.setFilter(new DefaultExtensionFilter(settings.getExtension())); - - rootNode.getChildren().add(node); - } - - return rootNode; - } - - protected RepositoryNode getRepositoryRootNode() { - return (RepositoryNode) getRootNode().getChildren().get(0); - } - - /** - * @see org.pivot4j.analytics.state.ViewStateListener#viewRegistered(org.pivot4j.analytics.state.ViewStateEvent) - */ - @Override - public void viewRegistered(ViewStateEvent e) { - final String viewId = e.getState().getId(); - final ReportFile file = e.getState().getFile(); - - if (file == null) { - return; - } - - RepositoryNode root = getRepositoryRootNode(); - RepositoryNode node = root.findNode(file); - - if (node != null) { - node.setViewId(viewId); - } - } - - /** - * @see org.pivot4j.analytics.state.ViewStateListener#viewUnregistered(org.pivot4j.analytics.state.ViewStateEvent) - */ - @Override - public void viewUnregistered(ViewStateEvent e) { - String viewId = e.getState().getId(); - - RepositoryNode root = getRepositoryRootNode(); - RepositoryNode node = root.findNode(viewId); - - if (node != null) { - node.setViewId(null); - } - } - - /** - * @return the activeViewId - */ - public ViewState getActiveView() { - if (activeViewId == null) { - return null; - } - - return viewStateHolder.getState(activeViewId); - } - - /** - * @return the activeViewId - */ - public String getActiveViewId() { - return activeViewId; - } - - /** - * @param activeViewId - * the activeViewId to set - */ - public void setActiveViewId(String activeViewId) { - this.activeViewId = activeViewId; - } - - /** - * @return the reportName - */ - public String getReportName() { - return reportName; - } - - /** - * @param reportName - * the reportName to set - */ - public void setReportName(String reportName) { - this.reportName = reportName; - } - - /** - * @return the folderName - */ - public String getFolderName() { - return folderName; - } - - /** - * @param folderName - * the folderName to set - */ - public void setFolderName(String folderName) { - this.folderName = folderName; - } - - /** - * @return the settings - */ - public Settings getSettings() { - return settings; - } - - /** - * @param settings - * the settings to set - */ - public void setSettings(Settings settings) { - this.settings = settings; - } - - /** - * @return the dataSourceManager - */ - public DataSourceManager getDataSourceManager() { - return dataSourceManager; - } - - /** - * @param dataSourceManager - * the dataSourceManager to set - */ - public void setDataSourceManager(DataSourceManager dataSourceManager) { - this.dataSourceManager = dataSourceManager; - } - - /** - * @return the viewStateHolder - */ - public ViewStateHolder getViewStateHolder() { - return viewStateHolder; - } - - /** - * @param viewStateHolder - * the viewStateHolder to set - */ - public void setViewStateHolder(ViewStateHolder viewStateHolder) { - this.viewStateHolder = viewStateHolder; - } - - /** - * @return the selection - */ - public TreeNode getSelection() { - return selection; - } - - /** - * @param selection - * the selection to set - */ - public void setSelection(TreeNode selection) { - this.selection = selection; - } - - public static class ViewInfo implements Serializable { - - private static final long serialVersionUID = 862747643432896517L; - - private String id; - - private String name; - - private String path; - - private boolean dirty; - - private boolean initialized; - - /** - * @param state - */ - ViewInfo(ViewState state) { - this.id = state.getId(); - this.name = state.getName(); - this.dirty = state.isDirty(); - this.initialized = state.getConnectionInfo() != null; - - if (state.getFile() != null) { - this.path = state.getFile().getPath(); - } - } - - /** - * @return the id - */ - public String getId() { - return id; - } - - /** - * @return the name - */ - public String getName() { - return name; - } - - /** - * @return the path - */ - public String getPath() { - return path; - } - - /** - * @return the dirty - */ - public boolean isDirty() { - return dirty; - } - - /** - * @return the initialized - */ - public boolean isInitialized() { - return initialized; - } - } - - static class DefaultExtensionFilter implements RepositoryFileFilter { - - private String extension; - - DefaultExtensionFilter(String extension) { - this.extension = StringUtils.trimToNull(extension); - } - - /** - * @see org.pivot4j.analytics.repository.RepositoryFileFilter#accept(org.pivot4j.analytics.repository.ReportFile) - */ - @Override - public boolean accept(ReportFile file) { - if (file.isDirectory() || extension == null) { - return true; - } else { - String value = file.getExtension(); - - return value != null && value.endsWith(extension); - } - } - } + /** + * @param file + */ + protected void delete(ReportFile file) { + try { + repository.deleteFile(file); + } catch (IOException e) { + FacesContext context = FacesContext.getCurrentInstance(); + ResourceBundle bundle = context.getApplication().getResourceBundle( + context, "msg"); + + String title = bundle.getString("error.delete.report.title"); + String message = bundle.getString("error.delete.report.message") + + e; + + context.addMessage(null, new FacesMessage( + FacesMessage.SEVERITY_ERROR, title, message)); + + if (log.isErrorEnabled()) { + log.error(title, e); + } + + return; + } + + if (selection instanceof RepositoryNode) { + RepositoryNode node = (RepositoryNode) selection; + if (node.getObject().equals(file)) { + selection.getParent().getChildren().remove(selection); + + this.selection = null; + } + } + } + + public void close() { + FacesContext context = FacesContext.getCurrentInstance(); + + Map parameters = context.getExternalContext() + .getRequestParameterMap(); + String viewId = parameters.get("viewId"); + + close(viewId); + } + + /** + * @param viewId + */ + public void close(String viewId) { + String viewToClose; + + if (viewId == null) { + viewToClose = this.activeViewId; + this.activeViewId = null; + } else { + viewToClose = viewId; + } + + ViewState view = viewStateHolder.getState(viewToClose); + int index = viewStateHolder.getStates().indexOf(view); + + viewStateHolder.unregisterState(viewToClose); + + PrimeFaces.current().executeScript(String.format("closeTab(%s)", index)); + } + + public boolean isOpenEnabled() { + if (selection != null) { + RepositoryNode node = (RepositoryNode) selection; + ReportFile file = node.getObject(); + + if (!file.isDirectory()) { + List states = viewStateHolder.getStates(); + for (ViewState state : states) { + if (file.equals(state.getFile())) { + return false; + } + } + + return true; + } + } + + return false; + } + + public boolean isDeleteEnabled() { + if (selection != null) { + RepositoryNode node = (RepositoryNode) selection; + ReportFile file = node.getObject(); + + return !file.isRoot(); + } + + return false; + } + + public void onTabChange() { + FacesContext context = FacesContext.getCurrentInstance(); + + Map parameters = context.getExternalContext() + .getRequestParameterMap(); + + select(parameters.get("viewId")); + } + + public void onSelectionChange() { + RepositoryNode root = getRepositoryRootNode(); + root.clearSelection(); + + if (selection != null) { + selection.setSelected(true); + } + } + + /** + * @param viewId + */ + protected void select(String viewId) { + this.activeViewId = viewId; + + ViewState state = viewStateHolder.getState(activeViewId); + + RepositoryNode root = getRepositoryRootNode(); + root.clearSelection(); + + if (state != null && state.getFile() != null) { + this.selection = root.selectNode(state.getFile()); + } + } + + public void onChange() { + ViewState state = getActiveView(); + if (state != null) { + state.setDirty(true); + } + } + + public void suggestNewName() { + FacesContext context = FacesContext.getCurrentInstance(); + ResourceBundle bundle = context.getApplication().getResourceBundle( + context, "msg"); + + String name = null; + + ViewState state = getActiveView(); + if (state != null) { + name = state.getName(); + } + + if (name == null) { + this.reportName = null; + return; + } + + String extension = settings.getExtension(); + + if (name.toLowerCase().endsWith(extension)) { + name = name.substring(0, name.length() - (extension.length() + 1)); + } + + ReportFile parent = getTargetDirectory(); + + Set names; + + try { + List children = repository.getFiles(parent); + + names = new HashSet(children.size()); + + for (ReportFile child : children) { + String childName = child.getName(); + + if (childName.toLowerCase().endsWith(extension)) { + childName = childName.substring(0, childName.length() - (extension.length() + 1)); + } + + names.add(childName); + } + } catch (IOException e) { + throw new FacesException(e); + } + + Pattern pattern = Pattern.compile("([^\\(]+)\\(([0-9]+)\\)"); + + while (names.contains(name)) { + Matcher matcher = pattern.matcher(name); + + if (matcher.matches()) { + String prefix = matcher.group(1); + int suffix = Integer.parseInt(matcher.group(2)) + 1; + + StringBuilder builder = new StringBuilder(); + builder.append(prefix); + builder.append("("); + builder.append(Integer.toString(suffix)); + builder.append(")"); + + name = builder.toString(); + } else { + name += "(2)"; + } + } + + this.reportName = name; + } + + protected ReportFile getTargetDirectory() { + ReportFile parent = null; + + if (selection != null) { + RepositoryNode node = (RepositoryNode) selection; + + ReportFile selectedFile = node.getObject(); + if (selectedFile.isDirectory()) { + parent = selectedFile; + } else { + try { + parent = selectedFile.getParent(); + } catch (IOException e) { + throw new FacesException(e); + } + } + } + + if (parent == null) { + try { + parent = repository.getRoot(); + } catch (IOException e) { + throw new FacesException(e); + } + } + + return parent; + } + + /** + * @return the rootNode + */ + public TreeNode getRootNode() { + if (rootNode == null) { + this.rootNode = new DefaultTreeNode(); + + rootNode.setExpanded(true); + + RepositoryNode node; + + try { + node = new RepositoryNode(repository.getRoot(), repository); + } catch (IOException e) { + throw new FacesException(e); + } + + node.setExpanded(true); + node.setFilter(new DefaultExtensionFilter(settings.getExtension())); + + rootNode.getChildren().add(node); + } + + return rootNode; + } + + protected RepositoryNode getRepositoryRootNode() { + return (RepositoryNode) getRootNode().getChildren().get(0); + } + + /** + * @see + * org.pivot4j.analytics.state.ViewStateListener#viewRegistered(org.pivot4j.analytics.state.ViewStateEvent) + */ + @Override + public void viewRegistered(ViewStateEvent e) { + final String viewId = e.getState().getId(); + final ReportFile file = e.getState().getFile(); + + if (file == null) { + return; + } + + RepositoryNode root = getRepositoryRootNode(); + RepositoryNode node = root.findNode(file); + + if (node != null) { + node.setViewId(viewId); + } + } + + /** + * @see + * org.pivot4j.analytics.state.ViewStateListener#viewUnregistered(org.pivot4j.analytics.state.ViewStateEvent) + */ + @Override + public void viewUnregistered(ViewStateEvent e) { + String viewId = e.getState().getId(); + + RepositoryNode root = getRepositoryRootNode(); + RepositoryNode node = root.findNode(viewId); + + if (node != null) { + node.setViewId(null); + } + } + + /** + * @return the activeViewId + */ + public ViewState getActiveView() { + if (activeViewId == null) { + return null; + } + + return viewStateHolder.getState(activeViewId); + } + + /** + * @return the activeViewId + */ + public String getActiveViewId() { + return activeViewId; + } + + /** + * @param activeViewId the activeViewId to set + */ + public void setActiveViewId(String activeViewId) { + this.activeViewId = activeViewId; + } + + /** + * @return the reportName + */ + public String getReportName() { + return reportName; + } + + /** + * @param reportName the reportName to set + */ + public void setReportName(String reportName) { + this.reportName = reportName; + } + + /** + * @return the folderName + */ + public String getFolderName() { + return folderName; + } + + /** + * @param folderName the folderName to set + */ + public void setFolderName(String folderName) { + this.folderName = folderName; + } + + /** + * @return the settings + */ + public Settings getSettings() { + return settings; + } + + /** + * @param settings the settings to set + */ + public void setSettings(Settings settings) { + this.settings = settings; + } + + /** + * @return the dataSourceManager + */ + public DataSourceManager getDataSourceManager() { + return dataSourceManager; + } + + /** + * @param dataSourceManager the dataSourceManager to set + */ + public void setDataSourceManager(DataSourceManager dataSourceManager) { + this.dataSourceManager = dataSourceManager; + } + + /** + * @return the viewStateHolder + */ + public ViewStateHolder getViewStateHolder() { + return viewStateHolder; + } + + /** + * @param viewStateHolder the viewStateHolder to set + */ + public void setViewStateHolder(ViewStateHolder viewStateHolder) { + this.viewStateHolder = viewStateHolder; + } + + /** + * @return the selection + */ + public TreeNode getSelection() { + return selection; + } + + /** + * @param selection the selection to set + */ + public void setSelection(TreeNode selection) { + this.selection = selection; + } + + public static class ViewInfo implements Serializable { + + private static final long serialVersionUID = 862747643432896517L; + + private String id; + + private String name; + + private String path; + + private boolean dirty; + + private boolean initialized; + + /** + * @param state + */ + ViewInfo(ViewState state) { + this.id = state.getId(); + this.name = state.getName(); + this.dirty = state.isDirty(); + this.initialized = state.getConnectionInfo() != null; + + if (state.getFile() != null) { + this.path = state.getFile().getPath(); + } + } + + /** + * @return the id + */ + public String getId() { + return id; + } + + /** + * @return the name + */ + public String getName() { + return name; + } + + /** + * @return the path + */ + public String getPath() { + return path; + } + + /** + * @return the dirty + */ + public boolean isDirty() { + return dirty; + } + + /** + * @return the initialized + */ + public boolean isInitialized() { + return initialized; + } + } + + static class DefaultExtensionFilter implements RepositoryFileFilter { + + private String extension; + + DefaultExtensionFilter(String extension) { + this.extension = StringUtils.trimToNull(extension); + } + + /** + * @see + * org.pivot4j.analytics.repository.RepositoryFileFilter#accept(org.pivot4j.analytics.repository.ReportFile) + */ + @Override + public boolean accept(ReportFile file) { + if (file.isDirectory() || extension == null) { + return true; + } else { + String value = file.getExtension(); + + return value != null && value.endsWith(extension); + } + } + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/SelectionMode.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/SelectionMode.java index 3071ddfa..70f17296 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/SelectionMode.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/SelectionMode.java @@ -11,106 +11,102 @@ public enum SelectionMode { - Single { - @Override - public List getTargetMembers(Member member) { - List selection = new ArrayList(1); - selection.add(member); - - return selection; - } - }, - - Level { - @Override - public List getTargetMembers(Member member) { - try { - return member.getLevel().getMembers(); - } catch (OlapException e) { - throw new FacesException(e); - } - } - }, - - Sibling { - @Override - public List getTargetMembers(Member member) { - try { - Member parent = member.getParentMember(); - - if (parent == null) { - return Single.getTargetMembers(member); - } - - List children = parent.getChildMembers(); - List selection = new ArrayList(children.size()); - - for (Member child : children) { - if (OlapUtils.isVisible(child)) { - selection.add(child); - } - } - - return selection; - } catch (OlapException e) { - throw new FacesException(e); - } - } - }, - - Children { - @Override - public List getTargetMembers(Member member) { - List selection = new ArrayList(); - selection.add(member); - - try { - List children = member.getChildMembers(); - - for (Member child : children) { - if (OlapUtils.isVisible(child)) { - selection.add(child); - } - } - } catch (OlapException e) { - throw new FacesException(e); - } - - return selection; - } - }, - - Descendants { - @Override - public List getTargetMembers(Member member) { - List selection = new ArrayList(); - - try { - if (OlapUtils.isVisible(member)) { - collectDescendants(member, selection); - } - } catch (OlapException e) { - throw new FacesException(e); - } - - return selection; - } - }; - - /** - * @param parent - * @param selection - */ - private static void collectDescendants(Member parent, List selection) - throws OlapException { - selection.add(parent); - - for (Member member : parent.getChildMembers()) { - if (OlapUtils.isVisible(member)) { - collectDescendants(member, selection); - } - } - } - - public abstract List getTargetMembers(Member member); -} \ No newline at end of file + Single { + @Override + public List getTargetMembers(Member member) { + List selection = new ArrayList(1); + selection.add(member); + + return selection; + } + }, + Level { + @Override + public List getTargetMembers(Member member) { + try { + return member.getLevel().getMembers(); + } catch (OlapException e) { + throw new FacesException(e); + } + } + }, + Sibling { + @Override + public List getTargetMembers(Member member) { + try { + Member parent = member.getParentMember(); + + if (parent == null) { + return Single.getTargetMembers(member); + } + + List children = parent.getChildMembers(); + List selection = new ArrayList(children.size()); + + for (Member child : children) { + if (OlapUtils.isVisible(child)) { + selection.add(child); + } + } + + return selection; + } catch (OlapException e) { + throw new FacesException(e); + } + } + }, + Children { + @Override + public List getTargetMembers(Member member) { + List selection = new ArrayList(); + selection.add(member); + + try { + List children = member.getChildMembers(); + + for (Member child : children) { + if (OlapUtils.isVisible(child)) { + selection.add(child); + } + } + } catch (OlapException e) { + throw new FacesException(e); + } + + return selection; + } + }, + Descendants { + @Override + public List getTargetMembers(Member member) { + List selection = new ArrayList(); + + try { + if (OlapUtils.isVisible(member)) { + collectDescendants(member, selection); + } + } catch (OlapException e) { + throw new FacesException(e); + } + + return selection; + } + }; + + /** + * @param parent + * @param selection + */ + private static void collectDescendants(Member parent, List selection) + throws OlapException { + selection.add(parent); + + for (Member member : parent.getChildMembers()) { + if (OlapUtils.isVisible(member)) { + collectDescendants(member, selection); + } + } + } + + public abstract List getTargetMembers(Member member); +} diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/ViewHandler.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/ViewHandler.java index 703dd4a2..889b14b7 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/ViewHandler.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/ViewHandler.java @@ -16,7 +16,6 @@ import javax.faces.component.UIInput; import javax.faces.component.UISelectItem; import javax.faces.context.FacesContext; - import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.exception.ExceptionUtils; @@ -47,7 +46,7 @@ import org.pivot4j.ui.command.UICommandParameters; import org.pivot4j.ui.table.TableRenderer; import org.pivot4j.util.OlapUtils; -import org.primefaces.context.RequestContext; +import org.primefaces.PrimeFaces; import org.primefaces.extensions.event.CloseEvent; import org.primefaces.extensions.event.OpenEvent; import org.primefaces.extensions.model.layout.LayoutOptions; @@ -811,6 +810,17 @@ public void setEditable(boolean editable) { stateManager.getState().setEditable(editable); } + public boolean isEnableMdx() { + return stateManager.getState().isEnableMdx(); + } + + /** + * @param enableMdx the editable to set + */ + public void setEnableMdx(boolean enableMdx) { + stateManager.getState().setEnableMdx(enableMdx); + } + /** * @return the swapAxes */ @@ -925,28 +935,32 @@ public void queryExecuted(QueryEvent e) { } /** - * @see org.pivot4j.ModelChangeListener#modelInitialized(org.pivot4j.ModelChangeEvent) + * @see + * org.pivot4j.ModelChangeListener#modelInitialized(org.pivot4j.ModelChangeEvent) */ @Override public void modelInitialized(ModelChangeEvent e) { } /** - * @see org.pivot4j.ModelChangeListener#modelDestroyed(org.pivot4j.ModelChangeEvent) + * @see + * org.pivot4j.ModelChangeListener#modelDestroyed(org.pivot4j.ModelChangeEvent) */ @Override public void modelDestroyed(ModelChangeEvent e) { } /** - * @see org.pivot4j.ModelChangeListener#modelChanged(org.pivot4j.ModelChangeEvent) + * @see + * org.pivot4j.ModelChangeListener#modelChanged(org.pivot4j.ModelChangeEvent) */ @Override public void modelChanged(ModelChangeEvent e) { } /** - * @see org.pivot4j.ModelChangeListener#structureChanged(org.pivot4j.ModelChangeEvent) + * @see + * org.pivot4j.ModelChangeListener#structureChanged(org.pivot4j.ModelChangeEvent) */ @Override public void structureChanged(ModelChangeEvent e) { @@ -963,12 +977,13 @@ public DrillThroughCommandImpl(PivotRenderer renderer) { } /** - * @see org.pivot4j.ui.command.BasicDrillThroughCommand#execute(org.pivot4j.PivotModel, + * @see + * org.pivot4j.ui.command.BasicDrillThroughCommand#execute(org.pivot4j.PivotModel, * org.pivot4j.ui.command.UICommandParameters) */ @Override public ResultSet execute(PivotModel model, - UICommandParameters parameters) { + UICommandParameters parameters) { int[] array = parameters.getCellCoordinate(); List coords = Arrays.asList(ArrayUtils.toObject(array)); @@ -976,9 +991,8 @@ public ResultSet execute(PivotModel model, drillThroughHandler.update(cell); - RequestContext context = RequestContext.getCurrentInstance(); - context.update("drillthrough-form"); - context.execute("PF('drillThroughDialog').show()"); + PrimeFaces.current().ajax().update("drillthrough-form"); + PrimeFaces.current().executeScript("PF('drillThroughDialog').show()"); return null; } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/WorkbenchHandler.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/WorkbenchHandler.java index ac3acf57..dc07168c 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/WorkbenchHandler.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/WorkbenchHandler.java @@ -15,130 +15,127 @@ @RequestScoped public class WorkbenchHandler { - @ManagedProperty(value = "#{settings}") - private Settings settings; - - @ManagedProperty(value = "#{repositoryHandler}") - private RepositoryHandler repositoryHandler; - - private LayoutOptions layoutOptions; - - /** - * @return the layoutOptions - */ - public LayoutOptions getLayoutOptions() { - if (layoutOptions == null) { - this.layoutOptions = new LayoutOptions(); - layoutOptions.addOption("enableCursorHotkey", false); - - LayoutOptions toolbarOptions = new LayoutOptions(); - toolbarOptions.addOption("resizable", false); - toolbarOptions.addOption("resizable", false); - toolbarOptions.addOption("closable", false); - - layoutOptions.setNorthOptions(toolbarOptions); - - LayoutOptions navigatorOptions = new LayoutOptions(); - navigatorOptions.addOption("resizable", true); - navigatorOptions.addOption("closable", true); - navigatorOptions.addOption("slidable", true); - navigatorOptions.addOption("size", 200); - - layoutOptions.setWestOptions(navigatorOptions); - - LayoutOptions contentOptions = new LayoutOptions(); - contentOptions.addOption("contentSelector", "#tab-panel"); - contentOptions.addOption("maskIframesOnResize", true); - - layoutOptions.setCenterOptions(contentOptions); - } - - return layoutOptions; - } - - /** - * @return the theme - */ - public String getTheme() { - ExternalContext context = FacesContext.getCurrentInstance() - .getExternalContext(); - String theme = (String) context.getSessionMap().get("ui-theme"); - - if (theme == null) { - theme = settings.getTheme(); - } - - return theme; - } - - /** - * @param theme - * the theme to set - */ - public void setTheme(String theme) { - ExternalContext context = FacesContext.getCurrentInstance() - .getExternalContext(); - - if (theme == null) { - context.getSessionMap().remove("ui-theme"); - } else { - context.getSessionMap().put("ui-theme", theme); - } - } - - public boolean isDeleteEnabled() { - ViewState viewState = repositoryHandler.getActiveView(); - return viewState != null && viewState.getFile() != null; - } - - public boolean isSaveEnabled() { - ViewState viewState = repositoryHandler.getActiveView(); - return viewState != null && viewState.isDirty(); - } - - public boolean isViewActive() { - ViewState viewState = repositoryHandler.getActiveView(); - return viewState != null; - } - - public boolean isViewValid() { - ViewState viewState = repositoryHandler.getActiveView(); - if (viewState == null) { - return false; - } - - PivotModel model = viewState.getModel(); - - return model != null && model.isInitialized(); - } - - /** - * @return the settings - */ - public Settings getSettings() { - return settings; - } - - /** - * @param settings - * the settings to set - */ - public void setSettings(Settings settings) { - this.settings = settings; - } - - /** - * @return the repositoryHandler - */ - public RepositoryHandler getRepositoryHandler() { - return repositoryHandler; - } - - /** - * @param repositoryHandler - * the repositoryHandler to set - */ - public void setRepositoryHandler(RepositoryHandler repositoryHandler) { - this.repositoryHandler = repositoryHandler; - } + @ManagedProperty(value = "#{settings}") + private Settings settings; + + @ManagedProperty(value = "#{repositoryHandler}") + private RepositoryHandler repositoryHandler; + + private LayoutOptions layoutOptions; + + /** + * @return the layoutOptions + */ + public LayoutOptions getLayoutOptions() { + if (layoutOptions == null) { + this.layoutOptions = new LayoutOptions(); + layoutOptions.addOption("enableCursorHotkey", false); + + LayoutOptions toolbarOptions = new LayoutOptions(); + toolbarOptions.addOption("resizable", false); + toolbarOptions.addOption("resizable", false); + toolbarOptions.addOption("closable", false); + + layoutOptions.setNorthOptions(toolbarOptions); + + LayoutOptions navigatorOptions = new LayoutOptions(); + navigatorOptions.addOption("resizable", true); + navigatorOptions.addOption("closable", true); + navigatorOptions.addOption("slidable", true); + navigatorOptions.addOption("size", 200); + + layoutOptions.setWestOptions(navigatorOptions); + + LayoutOptions contentOptions = new LayoutOptions(); + contentOptions.addOption("contentSelector", "#tab-panel"); + contentOptions.addOption("maskIframesOnResize", true); + + layoutOptions.setCenterOptions(contentOptions); + } + + return layoutOptions; + } + + /** + * @return the theme + */ + public String getTheme() { + ExternalContext context = FacesContext.getCurrentInstance() + .getExternalContext(); + String theme = (String) context.getSessionMap().get("ui-theme"); + + if (theme == null) { + theme = settings.getTheme(); + } + + return theme; + } + + /** + * @param theme the theme to set + */ + public void setTheme(String theme) { + ExternalContext context = FacesContext.getCurrentInstance() + .getExternalContext(); + + if (theme == null) { + context.getSessionMap().remove("ui-theme"); + } else { + context.getSessionMap().put("ui-theme", theme); + } + } + + public boolean isDeleteEnabled() { + ViewState viewState = repositoryHandler.getActiveView(); + return viewState != null && viewState.getFile() != null; + } + + public boolean isSaveEnabled() { + ViewState viewState = repositoryHandler.getActiveView(); + return viewState != null && viewState.isDirty(); + } + + public boolean isViewActive() { + ViewState viewState = repositoryHandler.getActiveView(); + return viewState != null; + } + + public boolean isViewValid() { + ViewState viewState = repositoryHandler.getActiveView(); + if (viewState == null) { + return false; + } + + PivotModel model = viewState.getModel(); + + return model != null && model.isInitialized(); + } + + /** + * @return the settings + */ + public Settings getSettings() { + return settings; + } + + /** + * @param settings the settings to set + */ + public void setSettings(Settings settings) { + this.settings = settings; + } + + /** + * @return the repositoryHandler + */ + public RepositoryHandler getRepositoryHandler() { + return repositoryHandler; + } + + /** + * @param repositoryHandler the repositoryHandler to set + */ + public void setRepositoryHandler(RepositoryHandler repositoryHandler) { + this.repositoryHandler = repositoryHandler; + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/AbstractCartesianChartBuilder.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/AbstractCartesianChartBuilder.java index 97b1cd3c..3f020ff5 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/AbstractCartesianChartBuilder.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/AbstractCartesianChartBuilder.java @@ -27,4 +27,4 @@ protected void configureChart(ChartRenderContext context, Chart chart, T model) model.getAxis(AxisType.X).setTickAngle(renderer.getXAxisAngle()); model.getAxis(AxisType.Y).setTickAngle(renderer.getYAxisAngle()); } -} \ No newline at end of file +} diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/AbstractChartBuilder.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/AbstractChartBuilder.java index 8f9c86c5..c0d8e6ff 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/AbstractChartBuilder.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/AbstractChartBuilder.java @@ -13,242 +13,248 @@ import org.primefaces.component.breadcrumb.BreadCrumb; import org.primefaces.component.chart.Chart; import org.primefaces.component.menuitem.UIMenuItem; -import org.primefaces.model.chart.AxisType; import org.primefaces.model.chart.ChartModel; public abstract class AbstractChartBuilder - extends AbstractRenderCallback implements - ChartBuilder { - - private FacesContext context; - - private UIComponent component; - - private HtmlPanelGrid pageComponent; - - private Chart chart; - - private T model; - - /** - * @param context - */ - public AbstractChartBuilder(FacesContext context) { - this.context = context; - } - - /** - * @return the context - */ - protected FacesContext getContext() { - return context; - } - - /** - * @return the component - */ - public UIComponent getComponent() { - return component; - } - - /** - * @param component - * the component to set - */ - public void setComponent(UIComponent component) { - this.component = component; - } - - /** - * @return the pageComponent - */ - protected HtmlPanelGrid getPageComponent() { - return pageComponent; - } - - /** - * @return the chart - */ - protected Chart getChart() { - return chart; - } - - /** - * @return the model - */ - protected T getModel() { - return model; - } - - /** - * @see org.pivot4j.ui.AbstractRenderCallback#startRender(org.pivot4j.ui.RenderContext) - */ - @Override - public void startRender(ChartRenderContext context) { - component.getChildren().clear(); - } - - /** - * @see org.pivot4j.ui.chart.ChartRenderCallback#startPage(org.pivot4j.ui.chart.ChartRenderContext) - */ - @Override - public void startPage(ChartRenderContext context) { - this.pageComponent = createPageComponent(context); - } - - /** - * @see org.pivot4j.ui.chart.ChartRenderCallback#startChart(org.pivot4j.ui.chart.ChartRenderContext) - */ - @Override - public void startChart(ChartRenderContext context) { - this.chart = createChart(context); - this.model = createModel(context); - - configureChart(context, chart, model); - } - - protected Chart createChart(ChartRenderContext context) { - return new Chart(); - } - - protected abstract T createModel(ChartRenderContext context); - - /** - * @param context - * @return - */ - protected BreadCrumb createBreadCrumb(ChartRenderContext context) { - BreadCrumb breadCrumb = new BreadCrumb(); - - UIMenuItem rootItem = new UIMenuItem(); - - rootItem.setValue(""); - breadCrumb.getChildren().add(rootItem); - - List members = context.getPagePath(); - - for (Member member : members) { - UIMenuItem item = new UIMenuItem(); - - item.setValue(member.getCaption()); - item.setTitle(member.getDescription()); - - breadCrumb.getChildren().add(item); - } - - return breadCrumb; - } - - /** - * @param context - * @return - */ - protected HtmlPanelGrid createPageComponent(ChartRenderContext context) { - DefaultChartRenderer renderer = (DefaultChartRenderer) context - .getRenderer(); - - HtmlPanelGrid grid = new HtmlPanelGrid(); - - if (renderer.getWidth() <= 0) { - grid.setStyle("width: 100%;"); - } - - grid.setStyleClass("chart-page"); - grid.setColumns(context.getChartCount()); - - return grid; - } - - /** - * @param context - * @param chart - * @param model - */ - protected void configureChart(ChartRenderContext context, Chart chart, T model) { - List path = context.getChartPath(); - - if (path != null && path.size() > 0) { - String title = path.get(path.size() - 1).getCaption(); - - model.setTitle(title); - } - - model.setShadow(true); - - DefaultChartRenderer renderer = (DefaultChartRenderer) context - .getRenderer(); - - if (renderer.getLegendPosition() != null) { - model.setLegendPosition(renderer.getLegendPosition().name()); - } - - StringBuilder builder = new StringBuilder(); - builder.append("width: "); - - if (renderer.getWidth() <= 0) { - builder.append("100%; "); - } else { - builder.append(Integer.toString(renderer.getWidth())); - builder.append("px; "); - } - - if (renderer.getHeight() > 0) { - builder.append("height: "); - builder.append(Integer.toString(renderer.getHeight())); - builder.append("px;"); - } - - chart.setStyle(builder.toString()); - chart.setType(getName().toLowerCase()); - } - - /** - * @see org.pivot4j.ui.chart.ChartRenderCallback#startSeries(org.pivot4j.ui.chart.ChartRenderContext) - */ - @Override - public void startSeries(ChartRenderContext context) { - } - - /** - * @see org.pivot4j.ui.RenderCallback#renderCommands(org.pivot4j.ui.RenderContext, - * java.util.List) - */ - @Override - public void renderCommands(ChartRenderContext context, - List> commands) { - } - - /** - * @see org.pivot4j.ui.chart.ChartRenderCallback#endSeries(org.pivot4j.ui.chart.ChartRenderContext) - */ - @Override - public void endSeries(ChartRenderContext context) { - } - - /** - * @see org.pivot4j.ui.chart.ChartRenderCallback#endChart(org.pivot4j.ui.chart.ChartRenderContext) - */ - @Override - public void endChart(ChartRenderContext context) { - chart.setModel(model); - - pageComponent.getChildren().add(chart); - - this.model = null; - this.chart = null; - } - - /** - * @see org.pivot4j.ui.chart.ChartRenderCallback#endPage(org.pivot4j.ui.chart.ChartRenderContext) - */ - @Override - public void endPage(ChartRenderContext context) { - if (!context.getPagePath().isEmpty()) { - pageComponent.getFacets().put("header", createBreadCrumb(context)); - } - - component.getChildren().add(pageComponent); - - this.pageComponent = null; - } -} \ No newline at end of file + extends AbstractRenderCallback implements + ChartBuilder { + + private FacesContext context; + + private UIComponent component; + + private HtmlPanelGrid pageComponent; + + private Chart chart; + + private T model; + + /** + * @param context + */ + public AbstractChartBuilder(FacesContext context) { + this.context = context; + } + + /** + * @return the context + */ + protected FacesContext getContext() { + return context; + } + + /** + * @return the component + */ + public UIComponent getComponent() { + return component; + } + + /** + * @param component the component to set + */ + public void setComponent(UIComponent component) { + this.component = component; + } + + /** + * @return the pageComponent + */ + protected HtmlPanelGrid getPageComponent() { + return pageComponent; + } + + /** + * @return the chart + */ + protected Chart getChart() { + return chart; + } + + /** + * @return the model + */ + protected T getModel() { + return model; + } + + /** + * @see + * org.pivot4j.ui.AbstractRenderCallback#startRender(org.pivot4j.ui.RenderContext) + */ + @Override + public void startRender(ChartRenderContext context) { + component.getChildren().clear(); + } + + /** + * @see + * org.pivot4j.ui.chart.ChartRenderCallback#startPage(org.pivot4j.ui.chart.ChartRenderContext) + */ + @Override + public void startPage(ChartRenderContext context) { + this.pageComponent = createPageComponent(context); + } + + /** + * @see + * org.pivot4j.ui.chart.ChartRenderCallback#startChart(org.pivot4j.ui.chart.ChartRenderContext) + */ + @Override + public void startChart(ChartRenderContext context) { + this.chart = createChart(context); + this.model = createModel(context); + + configureChart(context, chart, model); + } + + protected Chart createChart(ChartRenderContext context) { + return new Chart(); + } + + protected abstract T createModel(ChartRenderContext context); + + /** + * @param context + * @return + */ + protected BreadCrumb createBreadCrumb(ChartRenderContext context) { + BreadCrumb breadCrumb = new BreadCrumb(); + + UIMenuItem rootItem = new UIMenuItem(); + + rootItem.setValue(""); + breadCrumb.getChildren().add(rootItem); + + List members = context.getPagePath(); + + for (Member member : members) { + UIMenuItem item = new UIMenuItem(); + + item.setValue(member.getCaption()); + item.setTitle(member.getDescription()); + + breadCrumb.getChildren().add(item); + } + + return breadCrumb; + } + + /** + * @param context + * @return + */ + protected HtmlPanelGrid createPageComponent(ChartRenderContext context) { + DefaultChartRenderer renderer = (DefaultChartRenderer) context + .getRenderer(); + + HtmlPanelGrid grid = new HtmlPanelGrid(); + + if (renderer.getWidth() <= 0) { + grid.setStyle("width: 100%;"); + } + + grid.setStyleClass("chart-page"); + grid.setColumns(context.getChartCount()); + + return grid; + } + + /** + * @param context + * @param chart + * @param model + */ + protected void configureChart(ChartRenderContext context, Chart chart, T model) { + List path = context.getChartPath(); + + if (path != null && path.size() > 0) { + String title = path.get(path.size() - 1).getCaption(); + + model.setTitle(title); + } + + model.setShadow(true); + + DefaultChartRenderer renderer = (DefaultChartRenderer) context + .getRenderer(); + + if (renderer.getLegendPosition() != null) { + model.setLegendPosition(renderer.getLegendPosition().name()); + } + + StringBuilder builder = new StringBuilder(); + builder.append("width: "); + + if (renderer.getWidth() <= 0) { + builder.append("100%; "); + } else { + builder.append(Integer.toString(renderer.getWidth())); + builder.append("px; "); + } + + if (renderer.getHeight() > 0) { + builder.append("height: "); + builder.append(Integer.toString(renderer.getHeight())); + builder.append("px;"); + } + + chart.setStyle(builder.toString()); + chart.setType(getName().toLowerCase()); + } + + /** + * @see + * org.pivot4j.ui.chart.ChartRenderCallback#startSeries(org.pivot4j.ui.chart.ChartRenderContext) + */ + @Override + public void startSeries(ChartRenderContext context) { + } + + /** + * @see + * org.pivot4j.ui.RenderCallback#renderCommands(org.pivot4j.ui.RenderContext, + * java.util.List) + */ + @Override + public void renderCommands(ChartRenderContext context, + List> commands) { + } + + /** + * @see + * org.pivot4j.ui.chart.ChartRenderCallback#endSeries(org.pivot4j.ui.chart.ChartRenderContext) + */ + @Override + public void endSeries(ChartRenderContext context) { + } + + /** + * @see + * org.pivot4j.ui.chart.ChartRenderCallback#endChart(org.pivot4j.ui.chart.ChartRenderContext) + */ + @Override + public void endChart(ChartRenderContext context) { + chart.setModel(model); + + pageComponent.getChildren().add(chart); + + this.model = null; + this.chart = null; + } + + /** + * @see + * org.pivot4j.ui.chart.ChartRenderCallback#endPage(org.pivot4j.ui.chart.ChartRenderContext) + */ + @Override + public void endPage(ChartRenderContext context) { + if (!context.getPagePath().isEmpty()) { + pageComponent.getFacets().put("header", createBreadCrumb(context)); + } + + component.getChildren().add(pageComponent); + + this.pageComponent = null; + } +} diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/AbstractSeriesChartBuilder.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/AbstractSeriesChartBuilder.java index 22d51790..75daf7d0 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/AbstractSeriesChartBuilder.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/AbstractSeriesChartBuilder.java @@ -12,85 +12,88 @@ import org.primefaces.model.chart.ChartSeries; public abstract class AbstractSeriesChartBuilder - extends AbstractCartesianChartBuilder { - - private ChartSeries series; - - /** - * @param context - */ - public AbstractSeriesChartBuilder(FacesContext context) { - super(context); - } - - /** - * @return series - */ - protected ChartSeries getSeries() { - return series; - } - - protected ChartSeries createSeries() { - return new ChartSeries(); - } - - /** - * @see org.pivot4j.analytics.ui.chart.AbstractChartBuilder#startSeries(org.pivot4j.ui.chart.ChartRenderContext) - */ - @Override - public void startSeries(ChartRenderContext context) { - this.series = createSeries(); - - List path = new LinkedList(context.getSeriesPath()); - - if (!path.isEmpty() && context.getSeriesCount() > 1) { - String label; - - int size = path.size(); - if (size == 1) { - label = path.get(0).getCaption(); - } else { - StringBuilder builder = new StringBuilder(); - - boolean first = true; - for (Member member : path) { - if (first) { - first = false; - } else { - builder.append(ChartRenderer.DEFAULT_MEMBER_SEPARATOR); - } - - builder.append(member.getCaption()); - } - - label = builder.toString(); - } - - series.setLabel(label); - } - } - - /** - * @see org.pivot4j.ui.RenderCallback#renderContent(org.pivot4j.ui.RenderContext, - * java.lang.String, java.lang.Double) - */ - @Override - public void renderContent(ChartRenderContext context, String label, - Double value) { - if (series.getLabel() == null) { - series.setLabel(context.getMember().getHierarchy().getCaption()); - } - - series.set(label, value); - } - - /** - * @see org.pivot4j.analytics.ui.chart.AbstractChartBuilder#endSeries(org.pivot4j.ui.chart.ChartRenderContext) - */ - @Override - public void endSeries(ChartRenderContext context) { - getModel().addSeries(series); - - this.series = null; - } + extends AbstractCartesianChartBuilder { + + private ChartSeries series; + + /** + * @param context + */ + public AbstractSeriesChartBuilder(FacesContext context) { + super(context); + } + + /** + * @return series + */ + protected ChartSeries getSeries() { + return series; + } + + protected ChartSeries createSeries() { + return new ChartSeries(); + } + + /** + * @see + * org.pivot4j.analytics.ui.chart.AbstractChartBuilder#startSeries(org.pivot4j.ui.chart.ChartRenderContext) + */ + @Override + public void startSeries(ChartRenderContext context) { + this.series = createSeries(); + + List path = new LinkedList(context.getSeriesPath()); + + if (!path.isEmpty() && context.getSeriesCount() > 1) { + String label; + + int size = path.size(); + if (size == 1) { + label = path.get(0).getCaption(); + } else { + StringBuilder builder = new StringBuilder(); + + boolean first = true; + for (Member member : path) { + if (first) { + first = false; + } else { + builder.append(ChartRenderer.DEFAULT_MEMBER_SEPARATOR); + } + + builder.append(member.getCaption()); + } + + label = builder.toString(); + } + + series.setLabel(label); + } + } + + /** + * @see + * org.pivot4j.ui.RenderCallback#renderContent(org.pivot4j.ui.RenderContext, + * java.lang.String, java.lang.Double) + */ + @Override + public void renderContent(ChartRenderContext context, String label, + Double value) { + if (series.getLabel() == null) { + series.setLabel(context.getMember().getHierarchy().getCaption()); + } + + series.set(label, value); + } + + /** + * @see + * org.pivot4j.analytics.ui.chart.AbstractChartBuilder#endSeries(org.pivot4j.ui.chart.ChartRenderContext) + */ + @Override + public void endSeries(ChartRenderContext context) { + getModel().addSeries(series); + + this.series = null; + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/BarChartBuilder.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/BarChartBuilder.java index ddf4ac8e..9b764a96 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/BarChartBuilder.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/BarChartBuilder.java @@ -10,41 +10,43 @@ public class BarChartBuilder extends AbstractSeriesChartBuilder { - public static String NAME = "Bar"; - - /** - * @param context - */ - public BarChartBuilder(FacesContext context) { - super(context); - } - - /** - * @see org.pivot4j.analytics.ui.chart.ChartBuilder#getName() - */ - @Override - public String getName() { - return NAME; - } - - @Override - protected BarChartModel createModel(ChartRenderContext context) { - return new BarChartModel(); - } - - @Override - protected ChartSeries createSeries() { - return new BarChartSeries(); - } - - /** - * @see org.pivot4j.analytics.ui.chart.AbstractChartBuilder#configureChart(org.pivot4j.ui.chart.ChartRenderContext, - * org.primefaces.component.chart.Chart, org.primefaces.model.chart.ChartModel) - */ - @Override - protected void configureChart(ChartRenderContext context, Chart chart, BarChartModel model) { - super.configureChart(context, chart, model); - - model.setZoom(true); - } + public static String NAME = "Bar"; + + /** + * @param context + */ + public BarChartBuilder(FacesContext context) { + super(context); + } + + /** + * @see org.pivot4j.analytics.ui.chart.ChartBuilder#getName() + */ + @Override + public String getName() { + return NAME; + } + + @Override + protected BarChartModel createModel(ChartRenderContext context) { + return new BarChartModel(); + } + + @Override + protected ChartSeries createSeries() { + return new BarChartSeries(); + } + + /** + * @see + * org.pivot4j.analytics.ui.chart.AbstractChartBuilder#configureChart(org.pivot4j.ui.chart.ChartRenderContext, + * org.primefaces.component.chart.Chart, + * org.primefaces.model.chart.ChartModel) + */ + @Override + protected void configureChart(ChartRenderContext context, Chart chart, BarChartModel model) { + super.configureChart(context, chart, model); + + model.setZoom(true); + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/ChartBuilder.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/ChartBuilder.java index 66082db3..374d355c 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/ChartBuilder.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/ChartBuilder.java @@ -6,9 +6,9 @@ public interface ChartBuilder extends ChartRenderCallback { - String getName(); + String getName(); - UIComponent getComponent(); + UIComponent getComponent(); - void setComponent(UIComponent component); + void setComponent(UIComponent component); } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/ChartBuilderFactory.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/ChartBuilderFactory.java index 58419934..afa539e0 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/ChartBuilderFactory.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/ChartBuilderFactory.java @@ -1,5 +1,6 @@ package org.pivot4j.analytics.ui.chart; +import java.io.Serializable; import java.lang.reflect.Constructor; import java.util.LinkedHashMap; import java.util.LinkedList; @@ -14,65 +15,65 @@ @ManagedBean(name = "chartBuilderFactory") @ApplicationScoped -public class ChartBuilderFactory { +public class ChartBuilderFactory implements Serializable { - private Map> builders; + private transient Map> builders; - public ChartBuilderFactory() { - this.builders = new LinkedHashMap>(); + public ChartBuilderFactory() { + this.builders = new LinkedHashMap>(); - registerDefaultChartBuilders(builders); - } + registerDefaultChartBuilders(builders); + } - /** - * @param builders - */ - protected void registerDefaultChartBuilders( - Map> builders) { - builders.put(PieChartBuilder.NAME, PieChartBuilder.class); - builders.put(BarChartBuilder.NAME, BarChartBuilder.class); - builders.put(LineChartBuilder.NAME, LineChartBuilder.class); - builders.put(HorizontalBarChartBuilder.NAME, - HorizontalBarChartBuilder.class); - builders.put(StackedBarChartBuilder.NAME, StackedBarChartBuilder.class); - builders.put(StackedAreaChartBuilder.NAME, - StackedAreaChartBuilder.class); - } + /** + * @param builders + */ + protected void registerDefaultChartBuilders( + Map> builders) { + builders.put(PieChartBuilder.NAME, PieChartBuilder.class); + builders.put(BarChartBuilder.NAME, BarChartBuilder.class); + builders.put(LineChartBuilder.NAME, LineChartBuilder.class); + builders.put(HorizontalBarChartBuilder.NAME, + HorizontalBarChartBuilder.class); + builders.put(StackedBarChartBuilder.NAME, StackedBarChartBuilder.class); + builders.put(StackedAreaChartBuilder.NAME, + StackedAreaChartBuilder.class); + } - public List getBuilderNames() { - return new LinkedList(builders.keySet()); - } + public List getBuilderNames() { + return new LinkedList(builders.keySet()); + } - /** - * @param name - * @param context - * @return - */ - public T createChartBuilder(String name, - FacesContext context) { - T builder = null; + /** + * @param name + * @param context + * @return + */ + public T createChartBuilder(String name, + FacesContext context) { + T builder = null; - @SuppressWarnings("unchecked") - Class implementationType = (Class) builders.get(name); + @SuppressWarnings("unchecked") + Class implementationType = (Class) builders.get(name); - if (implementationType != null) { - try { - Constructor constructor = implementationType - .getConstructor(FacesContext.class); - builder = constructor.newInstance(context); - } catch (NoSuchMethodException e) { - String msg = "The registered implementation class does not have a suitable constructor : " - + implementationType; - throw new IllegalArgumentException(msg); - } catch (RuntimeException e) { - throw e; - } catch (Exception e) { - String msg = "Failed to instantiate the chart builder class : " - + implementationType; - throw new PivotException(msg, e); - } - } + if (implementationType != null) { + try { + Constructor constructor = implementationType + .getConstructor(FacesContext.class); + builder = constructor.newInstance(context); + } catch (NoSuchMethodException e) { + String msg = "The registered implementation class does not have a suitable constructor : " + + implementationType; + throw new IllegalArgumentException(msg); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + String msg = "Failed to instantiate the chart builder class : " + + implementationType; + throw new PivotException(msg, e); + } + } - return builder; - } + return builder; + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/ChartHandler.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/ChartHandler.java index 4ad68767..065d7bfb 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/ChartHandler.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/ChartHandler.java @@ -31,412 +31,403 @@ @ViewScoped public class ChartHandler implements ModelChangeListener, Serializable { - private static final long serialVersionUID = 8929886836467291035L; + private static final long serialVersionUID = 8929886836467291035L; - @ManagedProperty(value = "#{pivotStateManager}") - private PivotStateManager stateManager; + @ManagedProperty(value = "#{pivotStateManager}") + private PivotStateManager stateManager; - @ManagedProperty(value = "#{chartBuilderFactory}") - private ChartBuilderFactory chartBuilderFactory; + @ManagedProperty(value = "#{chartBuilderFactory}") + private ChartBuilderFactory chartBuilderFactory; - private PivotModel model; + private PivotModel model; - private DefaultChartRenderer renderer; + private DefaultChartRenderer renderer; - private HtmlPanelGroup component; + private HtmlPanelGroup component; - private List charts; + private List charts; - private Axis pageAxis; + private Axis pageAxis; - private Axis chartAxis; + private Axis chartAxis; - private Axis seriesAxis; + private Axis seriesAxis; - private Axis plotAxis; + private Axis plotAxis; - private int width; + private int width; - private int height; + private int height; - private Position legendPosition; + private Position legendPosition; - private int xAxisAngle; + private int xAxisAngle; - private int yAxisAngle; + private int yAxisAngle; + + @PostConstruct + protected void initialize() { + this.model = stateManager.getModel(); - @PostConstruct - protected void initialize() { - this.model = stateManager.getModel(); + if (model != null) { + model.addModelChangeListener(this); + } - if (model != null) { - model.addModelChangeListener(this); - } + this.renderer = new DefaultChartRenderer(); - this.renderer = new DefaultChartRenderer(); + Serializable state = stateManager.getChartState(); - Serializable state = stateManager.getChartState(); + if (state != null) { + renderer.restoreState(state); + } - if (state != null) { - renderer.restoreState(state); - } + this.charts = new LinkedList(); - this.charts = new LinkedList(); + reset(); - reset(); + FacesContext context = FacesContext.getCurrentInstance(); + + ResourceBundle resources = context.getApplication().getResourceBundle( + context, "msg"); - FacesContext context = FacesContext.getCurrentInstance(); - - ResourceBundle resources = context.getApplication().getResourceBundle( - context, "msg"); - - String prefix = "label.chart.items."; - - for (String builder : chartBuilderFactory.getBuilderNames()) { - charts.add(new SelectItem(builder, resources.getString(prefix - + builder))); - } - } - - @PreDestroy - protected void destroy() { - if (model != null) { - model.removeModelChangeListener(this); - } - } - - /** - * @return the renderer - */ - public ChartRenderer getRenderer() { - return renderer; - } - - /** - * @return the component - */ - public HtmlPanelGroup getComponent() { - return component; - } - - /** - * @param component - * the component to set - */ - public void setComponent(HtmlPanelGroup component) { - this.component = component; - } - - /** - * @return the stateManager - */ - public PivotStateManager getStateManager() { - return stateManager; - } - - /** - * @param stateManager - * the stateManager to set - */ - public void setStateManager(PivotStateManager stateManager) { - this.stateManager = stateManager; - } - - /** - * @return the chartBuilderFactory - */ - public ChartBuilderFactory getChartBuilderFactory() { - return chartBuilderFactory; - } - - /** - * @param chartBuilderFactory - * the chartBuilderFactory to set - */ - public void setChartBuilderFactory(ChartBuilderFactory chartBuilderFactory) { - this.chartBuilderFactory = chartBuilderFactory; - } - - /** - * @return the charts - */ - public List getCharts() { - return charts; - } - - /** - * @return the chartName - */ - public String getChartName() { - return renderer.getChartName(); - } - - /** - * @param chartName - * the chartName to set - */ - public void setChartName(String chartName) { - renderer.setChartName(chartName); - } - - /** - * @return the pageAxis - */ - public Axis getPageAxis() { - return pageAxis; - } - - /** - * @param pageAxis - * the pageAxis to set - */ - public void setPageAxis(Axis pageAxis) { - this.pageAxis = pageAxis; - } - - /** - * @return the chartAxis - */ - public Axis getChartAxis() { - return chartAxis; - } - - /** - * @param chartAxis - * the chartAxis to set - */ - public void setChartAxis(Axis chartAxis) { - this.chartAxis = chartAxis; - } - - /** - * @return the seriesAxis - */ - public Axis getSeriesAxis() { - return seriesAxis; - } - - /** - * @param seriesAxis - * the seriesAxis to set - */ - public void setSeriesAxis(Axis seriesAxis) { - this.seriesAxis = seriesAxis; - } - - /** - * @return the plotAxis - */ - public Axis getPlotAxis() { - return plotAxis; - } - - /** - * @param plotAxis - * the plotAxis to set - */ - public void setPlotAxis(Axis plotAxis) { - this.plotAxis = plotAxis; - } - - /** - * @return the width - */ - public int getWidth() { - return width; - } - - /** - * @param width - * the width to set - */ - public void setWidth(int width) { - this.width = width; - } - - /** - * @return the height - */ - public int getHeight() { - return height; - } - - /** - * @param height - * the height to set - */ - public void setHeight(int height) { - this.height = height; - } - - /** - * @return the legendPosition - */ - public Position getLegendPosition() { - return legendPosition; - } - - /** - * @param legendPosition - * the legendPosition to set - */ - public void setLegendPosition(Position legendPosition) { - this.legendPosition = legendPosition; - } - - /** - * @return the xAxisAngle - */ - public int getxAxisAngle() { - return xAxisAngle; - } - - /** - * @param xAxisAngle - * the xAxisAngle to set - */ - public void setxAxisAngle(int xAxisAngle) { - this.xAxisAngle = xAxisAngle; - } - - /** - * @return the yAxisAngle - */ - public int getyAxisAngle() { - return yAxisAngle; - } - - /** - * @param yAxisAngle - * the yAxisAngle to set - */ - public void setyAxisAngle(int yAxisAngle) { - this.yAxisAngle = yAxisAngle; - } - - public boolean isValid() { - if (model == null || !model.isInitialized()) { - return false; - } - - CellSet cellSet = model.getCellSet(); - - if (cellSet == null) { - return false; - } - - List axes = model.getCellSet().getAxes(); - if (axes.size() < 2) { - return false; - } - - return axes.get(0).getPositionCount() > 0 - && axes.get(1).getPositionCount() > 0; - } - - public void onPreRenderView() { - FacesContext context = FacesContext.getCurrentInstance(); - - if (!context.isPostback()) { - render(); - } - } - - public void reset() { - this.pageAxis = renderer.getPageAxis(); - this.chartAxis = renderer.getChartAxis(); - this.seriesAxis = renderer.getSeriesAxis(); - this.plotAxis = renderer.getPlotAxis(); - - this.width = renderer.getWidth(); - this.height = renderer.getHeight(); - this.xAxisAngle = renderer.getXAxisAngle(); - this.yAxisAngle = renderer.getYAxisAngle(); - this.legendPosition = renderer.getLegendPosition(); - } - - public void apply() { - boolean valid = false; - - valid |= pageAxis != null && !OlapUtils.equals(plotAxis, pageAxis); - valid |= chartAxis != null && !OlapUtils.equals(plotAxis, chartAxis); - valid |= seriesAxis != null && !OlapUtils.equals(plotAxis, seriesAxis); - - if (valid) { - renderer.setPageAxis(pageAxis); - renderer.setChartAxis(chartAxis); - renderer.setSeriesAxis(seriesAxis); - renderer.setPlotAxis(plotAxis); - - renderer.setWidth(width); - renderer.setHeight(height); - - renderer.setXAxisAngle(xAxisAngle); - renderer.setYAxisAngle(yAxisAngle); - - renderer.setLegendPosition(legendPosition); - - render(); - } else { - FacesContext context = FacesContext.getCurrentInstance(); - - ResourceBundle messages = context.getApplication() - .getResourceBundle(context, "msg"); - - String title = messages.getString("warn.chart.axis.unused.title"); - String msg = messages.getString("warn.chart.axis.unused.message"); - - context.addMessage("axis-plot", new FacesMessage( - FacesMessage.SEVERITY_WARN, title, msg)); - - } - } - - public void render() { - String chartName = getChartName(); - - if (model != null && model.isInitialized() - && StringUtils.isNotBlank(chartName)) { - FacesContext context = FacesContext.getCurrentInstance(); - - ChartBuilder builder = chartBuilderFactory.createChartBuilder( - chartName, context); - builder.setComponent(component); - - renderer.render(model, builder); - } - - if (renderer != null) { - stateManager.setChartState(renderer.saveState()); - } - } - - /** - * @see org.pivot4j.ModelChangeListener#modelInitialized(org.pivot4j.ModelChangeEvent) - */ - @Override - public void modelInitialized(ModelChangeEvent e) { - } - - /** - * @see org.pivot4j.ModelChangeListener#modelDestroyed(org.pivot4j.ModelChangeEvent) - */ - @Override - public void modelDestroyed(ModelChangeEvent e) { - } - - /** - * @see org.pivot4j.ModelChangeListener#modelChanged(org.pivot4j.ModelChangeEvent) - */ - @Override - public void modelChanged(ModelChangeEvent e) { - } - - /** - * @see org.pivot4j.ModelChangeListener#structureChanged(org.pivot4j.ModelChangeEvent) - */ - @Override - public void structureChanged(ModelChangeEvent e) { - render(); - } + String prefix = "label.chart.items."; + + for (String builder : chartBuilderFactory.getBuilderNames()) { + charts.add(new SelectItem(builder, resources.getString(prefix + + builder))); + } + } + + @PreDestroy + protected void destroy() { + if (model != null) { + model.removeModelChangeListener(this); + } + } + + /** + * @return the renderer + */ + public ChartRenderer getRenderer() { + return renderer; + } + + /** + * @return the component + */ + public HtmlPanelGroup getComponent() { + return component; + } + + /** + * @param component the component to set + */ + public void setComponent(HtmlPanelGroup component) { + this.component = component; + } + + /** + * @return the stateManager + */ + public PivotStateManager getStateManager() { + return stateManager; + } + + /** + * @param stateManager the stateManager to set + */ + public void setStateManager(PivotStateManager stateManager) { + this.stateManager = stateManager; + } + + /** + * @return the chartBuilderFactory + */ + public ChartBuilderFactory getChartBuilderFactory() { + return chartBuilderFactory; + } + + /** + * @param chartBuilderFactory the chartBuilderFactory to set + */ + public void setChartBuilderFactory(ChartBuilderFactory chartBuilderFactory) { + this.chartBuilderFactory = chartBuilderFactory; + } + + /** + * @return the charts + */ + public List getCharts() { + return charts; + } + + /** + * @return the chartName + */ + public String getChartName() { + return renderer.getChartName(); + } + + /** + * @param chartName the chartName to set + */ + public void setChartName(String chartName) { + renderer.setChartName(chartName); + } + + /** + * @return the pageAxis + */ + public Axis getPageAxis() { + return pageAxis; + } + + /** + * @param pageAxis the pageAxis to set + */ + public void setPageAxis(Axis pageAxis) { + this.pageAxis = pageAxis; + } + + /** + * @return the chartAxis + */ + public Axis getChartAxis() { + return chartAxis; + } + + /** + * @param chartAxis the chartAxis to set + */ + public void setChartAxis(Axis chartAxis) { + this.chartAxis = chartAxis; + } + + /** + * @return the seriesAxis + */ + public Axis getSeriesAxis() { + return seriesAxis; + } + + /** + * @param seriesAxis the seriesAxis to set + */ + public void setSeriesAxis(Axis seriesAxis) { + this.seriesAxis = seriesAxis; + } + + /** + * @return the plotAxis + */ + public Axis getPlotAxis() { + return plotAxis; + } + + /** + * @param plotAxis the plotAxis to set + */ + public void setPlotAxis(Axis plotAxis) { + this.plotAxis = plotAxis; + } + + /** + * @return the width + */ + public int getWidth() { + return width; + } + + /** + * @param width the width to set + */ + public void setWidth(int width) { + this.width = width; + } + + /** + * @return the height + */ + public int getHeight() { + return height; + } + + /** + * @param height the height to set + */ + public void setHeight(int height) { + this.height = height; + } + + /** + * @return the legendPosition + */ + public Position getLegendPosition() { + return legendPosition; + } + + /** + * @param legendPosition the legendPosition to set + */ + public void setLegendPosition(Position legendPosition) { + this.legendPosition = legendPosition; + } + + /** + * @return the xAxisAngle + */ + public int getxAxisAngle() { + return xAxisAngle; + } + + /** + * @param xAxisAngle the xAxisAngle to set + */ + public void setxAxisAngle(int xAxisAngle) { + this.xAxisAngle = xAxisAngle; + } + + /** + * @return the yAxisAngle + */ + public int getyAxisAngle() { + return yAxisAngle; + } + + /** + * @param yAxisAngle the yAxisAngle to set + */ + public void setyAxisAngle(int yAxisAngle) { + this.yAxisAngle = yAxisAngle; + } + + public boolean isValid() { + if (model == null || !model.isInitialized()) { + return false; + } + + CellSet cellSet = model.getCellSet(); + + if (cellSet == null) { + return false; + } + + List axes = model.getCellSet().getAxes(); + if (axes.size() < 2) { + return false; + } + + return axes.get(0).getPositionCount() > 0 + && axes.get(1).getPositionCount() > 0; + } + + public void onPreRenderView() { + FacesContext context = FacesContext.getCurrentInstance(); + + if (!context.isPostback()) { + render(); + } + } + + public void reset() { + this.pageAxis = renderer.getPageAxis(); + this.chartAxis = renderer.getChartAxis(); + this.seriesAxis = renderer.getSeriesAxis(); + this.plotAxis = renderer.getPlotAxis(); + + this.width = renderer.getWidth(); + this.height = renderer.getHeight(); + this.xAxisAngle = renderer.getXAxisAngle(); + this.yAxisAngle = renderer.getYAxisAngle(); + this.legendPosition = renderer.getLegendPosition(); + } + + public void apply() { + boolean valid = false; + + valid |= pageAxis != null && !OlapUtils.equals(plotAxis, pageAxis); + valid |= chartAxis != null && !OlapUtils.equals(plotAxis, chartAxis); + valid |= seriesAxis != null && !OlapUtils.equals(plotAxis, seriesAxis); + + if (valid) { + renderer.setPageAxis(pageAxis); + renderer.setChartAxis(chartAxis); + renderer.setSeriesAxis(seriesAxis); + renderer.setPlotAxis(plotAxis); + + renderer.setWidth(width); + renderer.setHeight(height); + + renderer.setXAxisAngle(xAxisAngle); + renderer.setYAxisAngle(yAxisAngle); + + renderer.setLegendPosition(legendPosition); + + render(); + } else { + FacesContext context = FacesContext.getCurrentInstance(); + + ResourceBundle messages = context.getApplication() + .getResourceBundle(context, "msg"); + + String title = messages.getString("warn.chart.axis.unused.title"); + String msg = messages.getString("warn.chart.axis.unused.message"); + + context.addMessage("axis-plot", new FacesMessage( + FacesMessage.SEVERITY_WARN, title, msg)); + + } + } + + public void render() { + String chartName = getChartName(); + + if (model != null && model.isInitialized() + && StringUtils.isNotBlank(chartName)) { + FacesContext context = FacesContext.getCurrentInstance(); + + ChartBuilder builder = chartBuilderFactory.createChartBuilder( + chartName, context); + builder.setComponent(component); + + renderer.render(model, builder); + } + + if (renderer != null) { + stateManager.setChartState(renderer.saveState()); + } + } + + /** + * @see + * org.pivot4j.ModelChangeListener#modelInitialized(org.pivot4j.ModelChangeEvent) + */ + @Override + public void modelInitialized(ModelChangeEvent e) { + } + + /** + * @see + * org.pivot4j.ModelChangeListener#modelDestroyed(org.pivot4j.ModelChangeEvent) + */ + @Override + public void modelDestroyed(ModelChangeEvent e) { + } + + /** + * @see + * org.pivot4j.ModelChangeListener#modelChanged(org.pivot4j.ModelChangeEvent) + */ + @Override + public void modelChanged(ModelChangeEvent e) { + } + + /** + * @see + * org.pivot4j.ModelChangeListener#structureChanged(org.pivot4j.ModelChangeEvent) + */ + @Override + public void structureChanged(ModelChangeEvent e) { + render(); + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/DefaultChartRenderer.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/DefaultChartRenderer.java index d5762bac..4601564f 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/DefaultChartRenderer.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/DefaultChartRenderer.java @@ -8,213 +8,210 @@ public class DefaultChartRenderer extends ChartRenderer { - private String chartName; - - private int width = 0; - - private int height = 300; - - private Position legendPosition = Position.w; - - private int xAxisAngle = 30; - - private int yAxisAngle = 0; - - /** - * @return the chartName - */ - public String getChartName() { - return chartName; - } - - /** - * @param chartName - * the chartName to set - */ - public void setChartName(String chartName) { - this.chartName = chartName; - } - - /** - * @return the width - */ - public int getWidth() { - return width; - } - - /** - * @param width - * the width to set - */ - public void setWidth(int width) { - this.width = width; - } - - /** - * @return the height - */ - public int getHeight() { - return height; - } - - /** - * @param height - * the height to set - */ - public void setHeight(int height) { - this.height = height; - } - - /** - * @return the legendPosition - */ - public Position getLegendPosition() { - return legendPosition; - } - - /** - * @param legendPosition - * the legendPosition to set - */ - public void setLegendPosition(Position legendPosition) { - this.legendPosition = legendPosition; - } - - /** - * @return the xAxisAngle - */ - public int getXAxisAngle() { - return xAxisAngle; - } - - /** - * @param xAxisAngle - * the xAxisAngle to set - */ - public void setXAxisAngle(int xAxisAngle) { - this.xAxisAngle = xAxisAngle; - } - - /** - * @return the yAxisAngle - */ - public int getYAxisAngle() { - return yAxisAngle; - } - - /** - * @param yAxisAngle - * the yAxisAngle to set - */ - public void setYAxisAngle(int yAxisAngle) { - this.yAxisAngle = yAxisAngle; - } - - /** - * @see org.pivot4j.ui.chart.ChartRenderer#saveState() - */ - @Override - public Serializable saveState() { - Serializable[] states = new Serializable[7]; - - int index = 0; - - states[index++] = super.saveState(); - states[index++] = chartName; - states[index++] = width; - states[index++] = height; - states[index++] = xAxisAngle; - states[index++] = yAxisAngle; - - String position = null; - - if (legendPosition != null) { - position = legendPosition.name(); - } - - states[index++] = position; - - return states; - } - - /** - * @see org.pivot4j.ui.chart.ChartRenderer#restoreState(java.io.Serializable) - */ - @Override - public void restoreState(Serializable state) { - Serializable[] states = (Serializable[]) state; - - int index = 0; - - super.restoreState(states[index++]); - - this.chartName = (String) states[index++]; - this.width = (Integer) states[index++]; - this.height = (Integer) states[index++]; - this.xAxisAngle = (Integer) states[index++]; - this.yAxisAngle = (Integer) states[index++]; - - String position = (String) states[index++]; - - if (position == null) { - this.legendPosition = null; - } else { - this.legendPosition = Position.valueOf(position); - } - } - - /** - * @see org.pivot4j.ui.chart.ChartRenderer#saveSettings(org.apache.commons.configuration.HierarchicalConfiguration) - */ - @Override - public void saveSettings(HierarchicalConfiguration configuration) { - super.saveSettings(configuration); - - configuration.addProperty("[@type]", chartName); - configuration.addProperty("dimension[@width]", width); - configuration.addProperty("dimension[@height]", height); - - configuration.addProperty("axes.axis(0)[@name]", "x"); - configuration.addProperty("axes.axis(0).label[@angle]", xAxisAngle); - - configuration.addProperty("axes.axis(1)[@name]", "y"); - configuration.addProperty("axes.axis(1).label[@angle]", yAxisAngle); - - if (legendPosition != null) { - configuration.addProperty("legend.position", legendPosition.name()); - } - } - - /** - * @see org.pivot4j.ui.chart.ChartRenderer#restoreSettings(org.apache.commons.configuration.HierarchicalConfiguration) - */ - @Override - public void restoreSettings(HierarchicalConfiguration configuration) { - super.restoreSettings(configuration); - - this.chartName = configuration.getString("[@type]"); - this.width = configuration.getInt("dimension[@width]", 0); - this.height = configuration.getInt("dimension[@height]", 0); - - List axisConfigs = configuration - .configurationsAt("axes.axis"); - - for (HierarchicalConfiguration axisConfig : axisConfigs) { - if (axisConfig.getString("[@name]", "x").equals("x")) { - this.xAxisAngle = axisConfig.getInt("label[@angle]", 30); - } else { - this.yAxisAngle = axisConfig.getInt("label[@angle]", 0); - } - } - - String position = configuration.getString("legend.position", - Position.w.name()); - - this.legendPosition = Position.valueOf(position); - } - - public enum Position { - - n, w, s, e - } + private String chartName; + + private int width = 0; + + private int height = 300; + + private Position legendPosition = Position.w; + + private int xAxisAngle = 30; + + private int yAxisAngle = 0; + + /** + * @return the chartName + */ + public String getChartName() { + return chartName; + } + + /** + * @param chartName the chartName to set + */ + public void setChartName(String chartName) { + this.chartName = chartName; + } + + /** + * @return the width + */ + public int getWidth() { + return width; + } + + /** + * @param width the width to set + */ + public void setWidth(int width) { + this.width = width; + } + + /** + * @return the height + */ + public int getHeight() { + return height; + } + + /** + * @param height the height to set + */ + public void setHeight(int height) { + this.height = height; + } + + /** + * @return the legendPosition + */ + public Position getLegendPosition() { + return legendPosition; + } + + /** + * @param legendPosition the legendPosition to set + */ + public void setLegendPosition(Position legendPosition) { + this.legendPosition = legendPosition; + } + + /** + * @return the xAxisAngle + */ + public int getXAxisAngle() { + return xAxisAngle; + } + + /** + * @param xAxisAngle the xAxisAngle to set + */ + public void setXAxisAngle(int xAxisAngle) { + this.xAxisAngle = xAxisAngle; + } + + /** + * @return the yAxisAngle + */ + public int getYAxisAngle() { + return yAxisAngle; + } + + /** + * @param yAxisAngle the yAxisAngle to set + */ + public void setYAxisAngle(int yAxisAngle) { + this.yAxisAngle = yAxisAngle; + } + + /** + * @see org.pivot4j.ui.chart.ChartRenderer#saveState() + */ + @Override + public Serializable saveState() { + Serializable[] states = new Serializable[7]; + + int index = 0; + + states[index++] = super.saveState(); + states[index++] = chartName; + states[index++] = width; + states[index++] = height; + states[index++] = xAxisAngle; + states[index++] = yAxisAngle; + + String position = null; + + if (legendPosition != null) { + position = legendPosition.name(); + } + + states[index++] = position; + + return states; + } + + /** + * @see + * org.pivot4j.ui.chart.ChartRenderer#restoreState(java.io.Serializable) + */ + @Override + public void restoreState(Serializable state) { + Serializable[] states = (Serializable[]) state; + + int index = 0; + + super.restoreState(states[index++]); + + this.chartName = (String) states[index++]; + this.width = (Integer) states[index++]; + this.height = (Integer) states[index++]; + this.xAxisAngle = (Integer) states[index++]; + this.yAxisAngle = (Integer) states[index++]; + + String position = (String) states[index++]; + + if (position == null) { + this.legendPosition = null; + } else { + this.legendPosition = Position.valueOf(position); + } + } + + /** + * @see + * org.pivot4j.ui.chart.ChartRenderer#saveSettings(org.apache.commons.configuration.HierarchicalConfiguration) + */ + @Override + public void saveSettings(HierarchicalConfiguration configuration) { + super.saveSettings(configuration); + + configuration.addProperty("[@type]", chartName); + configuration.addProperty("dimension[@width]", width); + configuration.addProperty("dimension[@height]", height); + + configuration.addProperty("axes.axis(0)[@name]", "x"); + configuration.addProperty("axes.axis(0).label[@angle]", xAxisAngle); + + configuration.addProperty("axes.axis(1)[@name]", "y"); + configuration.addProperty("axes.axis(1).label[@angle]", yAxisAngle); + + if (legendPosition != null) { + configuration.addProperty("legend.position", legendPosition.name()); + } + } + + /** + * @see + * org.pivot4j.ui.chart.ChartRenderer#restoreSettings(org.apache.commons.configuration.HierarchicalConfiguration) + */ + @Override + public void restoreSettings(HierarchicalConfiguration configuration) { + super.restoreSettings(configuration); + + this.chartName = configuration.getString("[@type]"); + this.width = configuration.getInt("dimension[@width]", 0); + this.height = configuration.getInt("dimension[@height]", 0); + + List axisConfigs = configuration + .configurationsAt("axes.axis"); + + for (HierarchicalConfiguration axisConfig : axisConfigs) { + if (axisConfig.getString("[@name]", "x").equals("x")) { + this.xAxisAngle = axisConfig.getInt("label[@angle]", 30); + } else { + this.yAxisAngle = axisConfig.getInt("label[@angle]", 0); + } + } + + String position = configuration.getString("legend.position", + Position.w.name()); + + this.legendPosition = Position.valueOf(position); + } + + public enum Position { + + n, w, s, e + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/HorizontalBarChartBuilder.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/HorizontalBarChartBuilder.java index 7b08d4b7..ad495aba 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/HorizontalBarChartBuilder.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/HorizontalBarChartBuilder.java @@ -9,37 +9,39 @@ public class HorizontalBarChartBuilder extends BarChartBuilder { - public static String NAME = "HorizontalBar"; - - /** - * @param context - */ - public HorizontalBarChartBuilder(FacesContext context) { - super(context); - } - - /** - * @see org.pivot4j.analytics.ui.chart.ChartBuilder#getName() - */ - @Override - public String getName() { - return NAME; - } - - @Override - protected BarChartModel createModel(ChartRenderContext context) { - return new HorizontalBarChartModel(); - } - - /** - * @see org.pivot4j.analytics.ui.chart.AbstractChartBuilder#configureChart(org.pivot4j.ui.chart.ChartRenderContext, - * org.primefaces.component.chart.Chart, org.primefaces.model.chart.ChartModel) - */ - @Override - protected void configureChart(ChartRenderContext context, Chart chart, BarChartModel model) { - super.configureChart(context, chart, model); - - chart.setType("bar"); - model.setLegendPosition("e"); - } + public static String NAME = "HorizontalBar"; + + /** + * @param context + */ + public HorizontalBarChartBuilder(FacesContext context) { + super(context); + } + + /** + * @see org.pivot4j.analytics.ui.chart.ChartBuilder#getName() + */ + @Override + public String getName() { + return NAME; + } + + @Override + protected BarChartModel createModel(ChartRenderContext context) { + return new HorizontalBarChartModel(); + } + + /** + * @see + * org.pivot4j.analytics.ui.chart.AbstractChartBuilder#configureChart(org.pivot4j.ui.chart.ChartRenderContext, + * org.primefaces.component.chart.Chart, + * org.primefaces.model.chart.ChartModel) + */ + @Override + protected void configureChart(ChartRenderContext context, Chart chart, BarChartModel model) { + super.configureChart(context, chart, model); + + chart.setType("bar"); + model.setLegendPosition("e"); + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/LineChartBuilder.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/LineChartBuilder.java index 7fc39019..bbe3eece 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/LineChartBuilder.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/LineChartBuilder.java @@ -8,43 +8,45 @@ public class LineChartBuilder extends AbstractSeriesChartBuilder { - public static String NAME = "Line"; - - /** - * @param context - */ - public LineChartBuilder(FacesContext context) { - super(context); - } - - /** - * @see org.pivot4j.analytics.ui.chart.ChartBuilder#getName() - */ - @Override - public String getName() { - return NAME; - } - - @Override - protected LineChartModel createModel(ChartRenderContext context) { - return new LineChartModel(); - } - - @Override - protected ChartSeries createSeries() { - return new LineChartSeries(); - } - - /** - * @see org.pivot4j.analytics.ui.chart.AbstractChartBuilder#configureChart(org.pivot4j.ui.chart.ChartRenderContext, - * org.primefaces.component.chart.Chart, org.primefaces.model.chart.ChartModel) - */ - @Override - protected void configureChart(ChartRenderContext context, Chart chart, LineChartModel model) { - super.configureChart(context, chart, model); - - model.setZoom(true); - model.setShowPointLabels(true); - model.getAxes().put(AxisType.X, new CategoryAxis("")); - } + public static String NAME = "Line"; + + /** + * @param context + */ + public LineChartBuilder(FacesContext context) { + super(context); + } + + /** + * @see org.pivot4j.analytics.ui.chart.ChartBuilder#getName() + */ + @Override + public String getName() { + return NAME; + } + + @Override + protected LineChartModel createModel(ChartRenderContext context) { + return new LineChartModel(); + } + + @Override + protected ChartSeries createSeries() { + return new LineChartSeries(); + } + + /** + * @see + * org.pivot4j.analytics.ui.chart.AbstractChartBuilder#configureChart(org.pivot4j.ui.chart.ChartRenderContext, + * org.primefaces.component.chart.Chart, + * org.primefaces.model.chart.ChartModel) + */ + @Override + protected void configureChart(ChartRenderContext context, Chart chart, LineChartModel model) { + super.configureChart(context, chart, model); + + model.setZoom(true); + model.setShowPointLabels(true); + model.getAxes().put(AxisType.X, new CategoryAxis("")); + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/PieChartBuilder.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/PieChartBuilder.java index 5134264b..3efac486 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/PieChartBuilder.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/PieChartBuilder.java @@ -8,51 +8,55 @@ public class PieChartBuilder extends AbstractChartBuilder { - public static String NAME = "Pie"; - - /** - * @param context - */ - public PieChartBuilder(FacesContext context) { - super(context); - } - - /** - * @see org.pivot4j.analytics.ui.chart.ChartBuilder#getName() - */ - @Override - public String getName() { - return NAME; - } - - /** - * @see org.pivot4j.analytics.ui.chart.AbstractChartBuilder#configureChart(org.pivot4j.ui.chart.ChartRenderContext, - * org.primefaces.component.chart.Chart, org.primefaces.model.chart.ChartModel) - */ - @Override - protected void configureChart(ChartRenderContext context, Chart chart, PieChartModel model) { - super.configureChart(context, chart, model); - - model.setShowDataLabels(true); - model.setDataFormat("value"); - model.setShadow(true); - } - - /** - * @see org.pivot4j.analytics.ui.chart.AbstractChartBuilder#createModel(org.pivot4j.ui.chart.ChartRenderContext) - */ - @Override - protected PieChartModel createModel(ChartRenderContext context) { - return new PieChartModel(); - } - - /** - * @see org.pivot4j.ui.RenderCallback#renderContent(org.pivot4j.ui.RenderContext, - * java.lang.String, java.lang.Double) - */ - @Override - public void renderContent(ChartRenderContext context, String label, - Double value) { - getModel().set(label, value); - } + public static String NAME = "Pie"; + + /** + * @param context + */ + public PieChartBuilder(FacesContext context) { + super(context); + } + + /** + * @see org.pivot4j.analytics.ui.chart.ChartBuilder#getName() + */ + @Override + public String getName() { + return NAME; + } + + /** + * @see + * org.pivot4j.analytics.ui.chart.AbstractChartBuilder#configureChart(org.pivot4j.ui.chart.ChartRenderContext, + * org.primefaces.component.chart.Chart, + * org.primefaces.model.chart.ChartModel) + */ + @Override + protected void configureChart(ChartRenderContext context, Chart chart, PieChartModel model) { + super.configureChart(context, chart, model); + + model.setShowDataLabels(true); + model.setShadow(true); + model.setShowDataLabels(true); + } + + /** + * @see + * org.pivot4j.analytics.ui.chart.AbstractChartBuilder#createModel(org.pivot4j.ui.chart.ChartRenderContext) + */ + @Override + protected PieChartModel createModel(ChartRenderContext context) { + return new PieChartModel(); + } + + /** + * @see + * org.pivot4j.ui.RenderCallback#renderContent(org.pivot4j.ui.RenderContext, + * java.lang.String, java.lang.Double) + */ + @Override + public void renderContent(ChartRenderContext context, String label, + Double value) { + getModel().set(label, value); + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/StackedAreaChartBuilder.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/StackedAreaChartBuilder.java index cae0e548..2e1c86aa 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/StackedAreaChartBuilder.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/StackedAreaChartBuilder.java @@ -10,42 +10,44 @@ public class StackedAreaChartBuilder extends LineChartBuilder { - public static String NAME = "StackedArea"; - - /** - * @param context - */ - public StackedAreaChartBuilder(FacesContext context) { - super(context); - } - - /** - * @see org.pivot4j.analytics.ui.chart.LineChartBuilder#getName() - */ - @Override - public String getName() { - return NAME; - } - - @Override - protected ChartSeries createSeries() { - LineChartSeries series = (LineChartSeries) super.createSeries(); - series.setFill(true); - - return series; - } - - /** - * @see org.pivot4j.analytics.ui.chart.AbstractChartBuilder#configureChart(org.pivot4j.ui.chart.ChartRenderContext, - * org.primefaces.component.chart.Chart, org.primefaces.model.chart.ChartModel) - */ - @Override - protected void configureChart(ChartRenderContext context, Chart chart, LineChartModel model) { - super.configureChart(context, chart, model); - - chart.setType("line"); - - model.setStacked(true); - model.setLegendPosition("n"); - } + public static String NAME = "StackedArea"; + + /** + * @param context + */ + public StackedAreaChartBuilder(FacesContext context) { + super(context); + } + + /** + * @see org.pivot4j.analytics.ui.chart.LineChartBuilder#getName() + */ + @Override + public String getName() { + return NAME; + } + + @Override + protected ChartSeries createSeries() { + LineChartSeries series = (LineChartSeries) super.createSeries(); + series.setFill(true); + + return series; + } + + /** + * @see + * org.pivot4j.analytics.ui.chart.AbstractChartBuilder#configureChart(org.pivot4j.ui.chart.ChartRenderContext, + * org.primefaces.component.chart.Chart, + * org.primefaces.model.chart.ChartModel) + */ + @Override + protected void configureChart(ChartRenderContext context, Chart chart, LineChartModel model) { + super.configureChart(context, chart, model); + + chart.setType("line"); + + model.setStacked(true); + model.setLegendPosition("n"); + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/StackedBarChartBuilder.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/StackedBarChartBuilder.java index 45a3c3ce..79bab5e2 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/StackedBarChartBuilder.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/chart/StackedBarChartBuilder.java @@ -8,32 +8,34 @@ public class StackedBarChartBuilder extends BarChartBuilder { - public static String NAME = "StackedBar"; - - /** - * @param context - */ - public StackedBarChartBuilder(FacesContext context) { - super(context); - } - - /** - * @see org.pivot4j.analytics.ui.chart.ChartBuilder#getName() - */ - @Override - public String getName() { - return NAME; - } - - /** - * @see org.pivot4j.analytics.ui.chart.AbstractChartBuilder#configureChart(org.pivot4j.ui.chart.ChartRenderContext, - * org.primefaces.component.chart.Chart, org.primefaces.model.chart.ChartModel) - */ - @Override - protected void configureChart(ChartRenderContext context, Chart chart, BarChartModel model) { - super.configureChart(context, chart, model); - - chart.setType("bar"); - model.setStacked(true); - } + public static String NAME = "StackedBar"; + + /** + * @param context + */ + public StackedBarChartBuilder(FacesContext context) { + super(context); + } + + /** + * @see org.pivot4j.analytics.ui.chart.ChartBuilder#getName() + */ + @Override + public String getName() { + return NAME; + } + + /** + * @see + * org.pivot4j.analytics.ui.chart.AbstractChartBuilder#configureChart(org.pivot4j.ui.chart.ChartRenderContext, + * org.primefaces.component.chart.Chart, + * org.primefaces.model.chart.ChartModel) + */ + @Override + protected void configureChart(ChartRenderContext context, Chart chart, BarChartModel model) { + super.configureChart(context, chart, model); + + chart.setType("bar"); + model.setStacked(true); + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/CubeNode.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/CubeNode.java index 92e93bf8..fb94bf5a 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/CubeNode.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/CubeNode.java @@ -11,66 +11,66 @@ public class CubeNode extends MetadataNode { - /** - * @param cube - */ - public CubeNode(Cube cube) { - super(cube); - } - - /** - * @see org.primefaces.model.TreeNode#getType() - */ - @Override - public String getType() { - return "cube"; - } - - /** - * @see org.primefaces.model.TreeNode#isLeaf() - */ - @Override - public boolean isLeaf() { - return false; - } - - /** - * @see org.pivot4j.analytics.ui.navigator.MetadataNode#createChildren() - */ - @Override - protected List createChildren() { - List dimensions = getObject().getDimensions(); - List children = new ArrayList(dimensions.size()); - - for (Dimension dimension : dimensions) { - if (!dimension.isVisible()) { - continue; - } - - MetadataElement element; - - MetadataNode node; - - Hierarchy defaultHierarchy = dimension.getDefaultHierarchy(); - - if (dimension.getHierarchies().size() == 1 - && defaultHierarchy.isVisible()) { - element = defaultHierarchy; - - node = new HierarchyNode((Hierarchy) element); - } else { - element = dimension; - - node = new DimensionNode(dimension); - } - - if (configureChildNode(element, node)) { - node.setParent(this); - - children.add(node); - } - } - - return children; - } + /** + * @param cube + */ + public CubeNode(Cube cube) { + super(cube); + } + + /** + * @see org.primefaces.model.TreeNode#getType() + */ + @Override + public String getType() { + return "cube"; + } + + /** + * @see org.primefaces.model.TreeNode#isLeaf() + */ + @Override + public boolean isLeaf() { + return false; + } + + /** + * @see org.pivot4j.analytics.ui.navigator.MetadataNode#createChildren() + */ + @Override + protected List createChildren() { + List dimensions = getObject().getDimensions(); + List children = new ArrayList(dimensions.size()); + + for (Dimension dimension : dimensions) { + if (!dimension.isVisible()) { + continue; + } + + MetadataElement element; + + MetadataNode node; + + Hierarchy defaultHierarchy = dimension.getDefaultHierarchy(); + + if (dimension.getHierarchies().size() == 1 + && defaultHierarchy.isVisible()) { + element = defaultHierarchy; + + node = new HierarchyNode((Hierarchy) element); + } else { + element = dimension; + + node = new DimensionNode(dimension); + } + + if (configureChildNode(element, node)) { + node.setParent(this); + + children.add(node); + } + } + + return children; + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/DimensionNode.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/DimensionNode.java index 2bbc72f7..f75b6447 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/DimensionNode.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/DimensionNode.java @@ -9,51 +9,51 @@ public class DimensionNode extends MetadataNode { - /** - * @param dimension - */ - public DimensionNode(Dimension dimension) { - super(dimension); - } - - /** - * @see org.primefaces.model.TreeNode#getType() - */ - @Override - public String getType() { - return "dimension"; - } - - /** - * @see org.primefaces.model.TreeNode#isLeaf() - */ - @Override - public boolean isLeaf() { - return false; - } - - /** - * @see org.pivot4j.analytics.ui.navigator.MetadataNode#createChildren() - */ - @Override - protected List createChildren() { - List hierarchies = getObject().getHierarchies(); - List children = new ArrayList(hierarchies.size()); - - for (Hierarchy hierarchy : hierarchies) { - if (!hierarchy.isVisible()) { - continue; - } - - HierarchyNode node = new HierarchyNode(hierarchy); - - if (configureChildNode(hierarchy, node)) { - node.setParent(this); - - children.add(node); - } - } - - return children; - } + /** + * @param dimension + */ + public DimensionNode(Dimension dimension) { + super(dimension); + } + + /** + * @see org.primefaces.model.TreeNode#getType() + */ + @Override + public String getType() { + return "dimension"; + } + + /** + * @see org.primefaces.model.TreeNode#isLeaf() + */ + @Override + public boolean isLeaf() { + return false; + } + + /** + * @see org.pivot4j.analytics.ui.navigator.MetadataNode#createChildren() + */ + @Override + protected List createChildren() { + List hierarchies = getObject().getHierarchies(); + List children = new ArrayList(hierarchies.size()); + + for (Hierarchy hierarchy : hierarchies) { + if (!hierarchy.isVisible()) { + continue; + } + + HierarchyNode node = new HierarchyNode(hierarchy); + + if (configureChildNode(hierarchy, node)) { + node.setParent(this); + + children.add(node); + } + } + + return children; + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/HierarchyNode.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/HierarchyNode.java index 594edff6..5c42ace7 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/HierarchyNode.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/HierarchyNode.java @@ -14,79 +14,79 @@ public class HierarchyNode extends MetadataNode { - /** - * @param hierarchy - */ - public HierarchyNode(Hierarchy hierarchy) { - super(hierarchy); - } - - /** - * @see org.primefaces.model.TreeNode#getType() - */ - @Override - public String getType() { - return "hierarchy"; - } - - /** - * @see org.primefaces.model.TreeNode#isLeaf() - */ - @Override - public boolean isLeaf() { - return false; - } - - /** - * @see org.pivot4j.analytics.ui.navigator.MetadataNode#createChildren() - */ - @Override - protected List createChildren() { - Hierarchy hierarchy = getObject(); - - try { - if (hierarchy.getDimension().getDimensionType() == Type.MEASURE) { - List members = hierarchy.getRootMembers(); - List children = new ArrayList( - members.size()); - - for (Member member : members) { - if (!member.isVisible()) { - continue; - } - - MeasureNode node = new MeasureNode(this, member); - - if (configureChildNode(member, node)) { - node.setParent(this); - - children.add(node); - } - } - - return children; - } else { - List levels = hierarchy.getLevels(); - List children = new ArrayList(levels.size()); - - for (Level level : levels) { - if (!level.isVisible()) { - continue; - } - - LevelNode node = new LevelNode(level); - - if (configureChildNode(level, node)) { - node.setParent(this); - - children.add(node); - } - } - - return children; - } - } catch (OlapException e) { - throw new FacesException(e); - } - } + /** + * @param hierarchy + */ + public HierarchyNode(Hierarchy hierarchy) { + super(hierarchy); + } + + /** + * @see org.primefaces.model.TreeNode#getType() + */ + @Override + public String getType() { + return "hierarchy"; + } + + /** + * @see org.primefaces.model.TreeNode#isLeaf() + */ + @Override + public boolean isLeaf() { + return false; + } + + /** + * @see org.pivot4j.analytics.ui.navigator.MetadataNode#createChildren() + */ + @Override + protected List createChildren() { + Hierarchy hierarchy = getObject(); + + try { + if (hierarchy.getDimension().getDimensionType() == Type.MEASURE) { + List members = hierarchy.getRootMembers(); + List children = new ArrayList( + members.size()); + + for (Member member : members) { + if (!member.isVisible()) { + continue; + } + + MeasureNode node = new MeasureNode(this, member); + + if (configureChildNode(member, node)) { + node.setParent(this); + + children.add(node); + } + } + + return children; + } else { + List levels = hierarchy.getLevels(); + List children = new ArrayList(levels.size()); + + for (Level level : levels) { + if (!level.isVisible()) { + continue; + } + + LevelNode node = new LevelNode(level); + + if (configureChildNode(level, node)) { + node.setParent(this); + + children.add(node); + } + } + + return children; + } + } catch (OlapException e) { + throw new FacesException(e); + } + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/LevelNode.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/LevelNode.java index 30644017..a037a5c9 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/LevelNode.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/LevelNode.java @@ -9,44 +9,45 @@ public class LevelNode extends MetadataNode { - /** - * @param level - */ - public LevelNode(Level level) { - super(level); - } - - /** - * @param level - * @return - * @see org.pivot4j.analytics.ui.navigator.MetadataNode#createData(org.olap4j.metadata.MetadataElement) - */ - @Override - protected NodeData createData(Level level) { - return new LevelNodeData(level); - } - - /** - * @see org.primefaces.model.TreeNode#getType() - */ - @Override - public String getType() { - return "level"; - } - - /** - * @see org.primefaces.model.TreeNode#isLeaf() - */ - @Override - public boolean isLeaf() { - return true; - } - - /** - * @see org.pivot4j.analytics.ui.navigator.MetadataNode#createChildren() - */ - @Override - protected List createChildren() { - return Collections.emptyList(); - } + /** + * @param level + */ + public LevelNode(Level level) { + super(level); + } + + /** + * @param level + * @return + * @see + * org.pivot4j.analytics.ui.navigator.MetadataNode#createData(org.olap4j.metadata.MetadataElement) + */ + @Override + protected NodeData createData(Level level) { + return new LevelNodeData(level); + } + + /** + * @see org.primefaces.model.TreeNode#getType() + */ + @Override + public String getType() { + return "level"; + } + + /** + * @see org.primefaces.model.TreeNode#isLeaf() + */ + @Override + public boolean isLeaf() { + return true; + } + + /** + * @see org.pivot4j.analytics.ui.navigator.MetadataNode#createChildren() + */ + @Override + protected List createChildren() { + return Collections.emptyList(); + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/LevelNodeData.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/LevelNodeData.java index f8d361a0..d3594b70 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/LevelNodeData.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/LevelNodeData.java @@ -5,33 +5,32 @@ public class LevelNodeData extends NodeData { - private static final long serialVersionUID = 1538439140022459634L; - - private int depth; - - public LevelNodeData() { - } - - /** - * @param level - */ - public LevelNodeData(Level level) { - super(level.getUniqueName(), level.getCaption()); - this.depth = level.getDepth(); - } - - /** - * @return the depth - */ - public int getDepth() { - return depth; - } - - /** - * @param depth - * the depth to set - */ - public void setDepth(int depth) { - this.depth = depth; - } + private static final long serialVersionUID = 1538439140022459634L; + + private int depth; + + public LevelNodeData() { + } + + /** + * @param level + */ + public LevelNodeData(Level level) { + super(level.getUniqueName(), level.getCaption()); + this.depth = level.getDepth(); + } + + /** + * @return the depth + */ + public int getDepth() { + return depth; + } + + /** + * @param depth the depth to set + */ + public void setDepth(int depth) { + this.depth = depth; + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/MeasureNode.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/MeasureNode.java index 00ea0333..0f31a1ee 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/MeasureNode.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/MeasureNode.java @@ -8,36 +8,36 @@ public class MeasureNode extends MetadataNode { - /** - * @param parent - * @param member - */ - public MeasureNode(TreeNode parent, Member member) { - super(member); - setParent(parent); - } + /** + * @param parent + * @param member + */ + public MeasureNode(TreeNode parent, Member member) { + super(member); + setParent(parent); + } - /** - * @see org.primefaces.model.TreeNode#getType() - */ - @Override - public String getType() { - return "measure"; - } + /** + * @see org.primefaces.model.TreeNode#getType() + */ + @Override + public String getType() { + return "measure"; + } - /** - * @see org.primefaces.model.TreeNode#isLeaf() - */ - @Override - public boolean isLeaf() { - return true; - } + /** + * @see org.primefaces.model.TreeNode#isLeaf() + */ + @Override + public boolean isLeaf() { + return true; + } - /** - * @see org.pivot4j.analytics.ui.navigator.MetadataNode#createChildren() - */ - @Override - protected List createChildren() { - return Collections.emptyList(); - } + /** + * @see org.pivot4j.analytics.ui.navigator.MetadataNode#createChildren() + */ + @Override + protected List createChildren() { + return Collections.emptyList(); + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/MemberNode.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/MemberNode.java index aba8856a..1db148f8 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/MemberNode.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/MemberNode.java @@ -12,55 +12,55 @@ public class MemberNode extends MetadataNode { - /** - * @param member - */ - public MemberNode(Member member) { - super(member); - } + /** + * @param member + */ + public MemberNode(Member member) { + super(member); + } - /** - * @see org.primefaces.model.TreeNode#getType() - */ - @Override - public String getType() { - return "member"; - } + /** + * @see org.primefaces.model.TreeNode#getType() + */ + @Override + public String getType() { + return "member"; + } - /** - * @see org.primefaces.model.TreeNode#isLeaf() - */ - @Override - public boolean isLeaf() { - try { - return getObject().getChildMemberCount() == 0; - } catch (OlapException e) { - throw new FacesException(e); - } - } + /** + * @see org.primefaces.model.TreeNode#isLeaf() + */ + @Override + public boolean isLeaf() { + try { + return getObject().getChildMemberCount() == 0; + } catch (OlapException e) { + throw new FacesException(e); + } + } - /** - * @see org.pivot4j.analytics.ui.navigator.MetadataNode#createChildren() - */ - @Override - protected List createChildren() { - try { - List members = getObject().getChildMembers(); - List children = new ArrayList(members.size()); + /** + * @see org.pivot4j.analytics.ui.navigator.MetadataNode#createChildren() + */ + @Override + protected List createChildren() { + try { + List members = getObject().getChildMembers(); + List children = new ArrayList(members.size()); - for (Member member : members) { - if (OlapUtils.isVisible(member)) { - MemberNode node = new MemberNode(member); + for (Member member : members) { + if (OlapUtils.isVisible(member)) { + MemberNode node = new MemberNode(member); - if (configureChildNode(member, node)) { - children.add(node); - } - } - } + if (configureChildNode(member, node)) { + children.add(node); + } + } + } - return children; - } catch (OlapException e) { - throw new FacesException(e); - } - } + return children; + } catch (OlapException e) { + throw new FacesException(e); + } + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/MetadataNode.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/MetadataNode.java index afbcdaa6..431b151b 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/MetadataNode.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/MetadataNode.java @@ -5,24 +5,25 @@ import org.pivot4j.analytics.component.tree.NodeData; public abstract class MetadataNode extends - LazyTreeNode { + LazyTreeNode { - /** - * @param object - */ - public MetadataNode(T object) { - super(object); - } + /** + * @param object + */ + public MetadataNode(T object) { + super(object); + } - /** - * @see org.pivot4j.analytics.component.tree.LazyTreeNode#createData(java.lang.Object) - */ - @Override - protected NodeData createData(T object) { - return new NodeData(object.getUniqueName(), object.getCaption()); - } + /** + * @see + * org.pivot4j.analytics.component.tree.LazyTreeNode#createData(java.lang.Object) + */ + @Override + protected NodeData createData(T object) { + return new NodeData(object.getUniqueName(), object.getCaption()); + } - @Override - public void setType(String type) { - } + @Override + public void setType(String type) { + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/RepositoryNode.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/RepositoryNode.java index d59398e3..b24df8b8 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/RepositoryNode.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/RepositoryNode.java @@ -24,333 +24,334 @@ import org.primefaces.model.TreeNode; public class RepositoryNode extends LazyTreeNode implements - StateHolder { - - private ReportRepository repository; - - private RepositoryFileFilter filter; - - private boolean transientState = false; - - private String viewId; - - public RepositoryNode() { - ExternalContext externalContext = FacesContext.getCurrentInstance() - .getExternalContext(); - Map applicationMap = externalContext - .getApplicationMap(); - - this.repository = (ReportRepository) applicationMap - .get("reportRepository"); - } - - /** - * @param file - * @param repository - */ - public RepositoryNode(ReportFile file, ReportRepository repository) { - super(file); - - if (repository == null) { - throw new NullArgumentException("repository"); - } - - this.repository = repository; - - setSelectable(true); - } - - /** - * @return the repository - */ - public ReportRepository getRepository() { - return repository; - } - - /** - * @see org.primefaces.model.TreeNode#getType() - */ - @Override - public String getType() { - String type; - - if (getObject().isRoot()) { - type = "root"; - } else if (getObject().isDirectory()) { - type = "directory"; - } else { - type = "file"; - } - - return type; - } - - @Override - public void setType(String type) { - } - - /** - * @see org.primefaces.model.TreeNode#isLeaf() - */ - @Override - public boolean isLeaf() { - return !getObject().isDirectory() || getChildCount() == 0; - } - - /** - * @return the viewId - */ - public String getViewId() { - return viewId; - } - - /** - * @param viewId - * the viewId to set - */ - public void setViewId(String viewId) { - this.viewId = viewId; - - getData().setSelected(viewId != null); - } - - /** - * @return the filter - */ - public RepositoryFileFilter getFilter() { - return filter; - } - - /** - * @param filter - * the filter to set - */ - public void setFilter(RepositoryFileFilter filter) { - this.filter = filter; - } - - /** - * @see org.pivot4j.analytics.component.tree.LazyTreeNode#createData(java.lang.Object) - */ - @Override - protected NodeData createData(ReportFile object) { - return new NodeData(object.getPath(), object.getName()); - } - - /** - * @see org.pivot4j.analytics.component.tree.LazyTreeNode#createChildren() - */ - @Override - protected List createChildren() { - List children; - - try { - List files = repository.getFiles(getObject()); - - children = new ArrayList(files.size()); - - for (ReportFile file : files) { - if (filter == null || filter.accept(file)) { - RepositoryNode child = new RepositoryNode(file, repository); - child.setParent(this); - child.setFilter(filter); - - children.add(child); - } - } - } catch (IOException e) { - throw new FacesException(e); - } - - return children; - } - - /** - * @param file - */ - public RepositoryNode selectNode(ReportFile file) { - RepositoryNode node = findNode(file); - - if (node != null) { - node.setSelected(true); - - TreeNode parent = node; - - while ((parent = parent.getParent()) != null) { - parent.setExpanded(true); - } - } - - return node; - } - - /** - * @param file - */ - public RepositoryNode findNode(ReportFile file) { - if (file == null) { - throw new NullArgumentException("file"); - } - - RepositoryNode selectedNode = null; - - List ancestors; - - try { - ancestors = file.getAncestors(); - } catch (IOException e) { - throw new FacesException(e); - } - - ReportFile thisFile = getObject(); - - if (file.equals(thisFile)) { - selectedNode = this; - } else if (ancestors.contains(thisFile)) { - for (TreeNode node : getChildren()) { - RepositoryNode fileNode = (RepositoryNode) node; - - selectedNode = fileNode.findNode(file); - - if (selectedNode != null) { - break; - } - } - } - - return selectedNode; - } - - /** - * @param viewId - */ - public RepositoryNode findNode(String viewId) { - if (viewId == null) { - throw new NullArgumentException("viewId"); - } - - RepositoryNode selectedNode = null; - - if (viewId.equals(this.viewId)) { - selectedNode = this; - } else if (isLoaded()) { - for (TreeNode node : getChildren()) { - RepositoryNode fileNode = (RepositoryNode) node; - - selectedNode = fileNode.findNode(viewId); - - if (selectedNode != null) { - break; - } - } - } - - return selectedNode; - } - - /** - * @see javax.faces.component.StateHolder#isTransient() - */ - @Override - public boolean isTransient() { - return transientState; - } - - /** - * @see javax.faces.component.StateHolder#setTransient(boolean) - */ - @Override - public void setTransient(boolean newTransientValue) { - this.transientState = newTransientValue; - } - - /** - * @see javax.faces.component.StateHolder#saveState(javax.faces.context.FacesContext) - */ - @Override - public Object saveState(FacesContext context) { - List states = new LinkedList(); - - states.add(isSelectable()); - states.add(isSelected()); - states.add(isExpanded()); - states.add(viewId); - states.add(getObject().getPath()); - - if (filter instanceof Serializable) { - states.add(filter); - } - - return states.toArray(new Object[states.size()]); - } - - /** - * @see javax.faces.component.StateHolder#restoreState(javax.faces.context.FacesContext, - * java.lang.Object) - */ - @Override - public void restoreState(FacesContext context, Object state) { - Object[] states = (Object[]) state; - - if (repository == null) { - Application application = context.getApplication(); - this.repository = application.evaluateExpressionGet(context, - "#{reportRepository}", ReportRepository.class); - } - - try { - setObject(repository.getFile((String) states[4])); - } catch (IOException e) { - throw new FacesException(e); - } - - setSelectable((Boolean) states[0]); - setSelected((Boolean) states[1]); - setExpanded((Boolean) states[2]); - setViewId((String) states[3]); - - if (states.length > 5) { - this.filter = (RepositoryFileFilter) states[5]; - } - } - - /** - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - return new HashCodeBuilder().append(getObject()).append(repository) - .toHashCode(); - } - - /** - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - - if (obj == null) { - return false; - } - - if (getClass() != obj.getClass()) { - return false; - } - - RepositoryNode other = (RepositoryNode) obj; - - return new EqualsBuilder().append(getObject(), other.getObject()) - .append(repository, other.repository).isEquals(); - } - - /** - * @see java.lang.Object#toString() - */ - @Override - public String toString() { - return getObject().toString(); - } + StateHolder { + + private ReportRepository repository; + + private RepositoryFileFilter filter; + + private boolean transientState = false; + + private String viewId; + + public RepositoryNode() { + ExternalContext externalContext = FacesContext.getCurrentInstance() + .getExternalContext(); + Map applicationMap = externalContext + .getApplicationMap(); + + this.repository = (ReportRepository) applicationMap + .get("reportRepository"); + } + + /** + * @param file + * @param repository + */ + public RepositoryNode(ReportFile file, ReportRepository repository) { + super(file); + + if (repository == null) { + throw new NullArgumentException("repository"); + } + + this.repository = repository; + + setSelectable(true); + } + + /** + * @return the repository + */ + public ReportRepository getRepository() { + return repository; + } + + /** + * @see org.primefaces.model.TreeNode#getType() + */ + @Override + public String getType() { + String type; + + if (getObject().isRoot()) { + type = "root"; + } else if (getObject().isDirectory()) { + type = "directory"; + } else { + type = "file"; + } + + return type; + } + + @Override + public void setType(String type) { + } + + /** + * @see org.primefaces.model.TreeNode#isLeaf() + */ + @Override + public boolean isLeaf() { + return !getObject().isDirectory() || getChildCount() == 0; + } + + /** + * @return the viewId + */ + public String getViewId() { + return viewId; + } + + /** + * @param viewId the viewId to set + */ + public void setViewId(String viewId) { + this.viewId = viewId; + + getData().setSelected(viewId != null); + } + + /** + * @return the filter + */ + public RepositoryFileFilter getFilter() { + return filter; + } + + /** + * @param filter the filter to set + */ + public void setFilter(RepositoryFileFilter filter) { + this.filter = filter; + } + + /** + * @see + * org.pivot4j.analytics.component.tree.LazyTreeNode#createData(java.lang.Object) + */ + @Override + protected NodeData createData(ReportFile object) { + return new NodeData(object.getPath(), object.getName()); + } + + /** + * @see org.pivot4j.analytics.component.tree.LazyTreeNode#createChildren() + */ + @Override + protected List createChildren() { + List children; + + try { + List files = repository.getFiles(getObject()); + + children = new ArrayList(files.size()); + + for (ReportFile file : files) { + if (filter == null || filter.accept(file)) { + RepositoryNode child = new RepositoryNode(file, repository); + child.setParent(this); + child.setFilter(filter); + + children.add(child); + } + } + } catch (IOException e) { + throw new FacesException(e); + } + + return children; + } + + /** + * @param file + */ + public RepositoryNode selectNode(ReportFile file) { + RepositoryNode node = findNode(file); + + if (node != null) { + node.setSelected(true); + + TreeNode parent = node; + + while ((parent = parent.getParent()) != null) { + parent.setExpanded(true); + } + } + + return node; + } + + /** + * @param file + */ + public RepositoryNode findNode(ReportFile file) { + if (file == null) { + throw new NullArgumentException("file"); + } + + RepositoryNode selectedNode = null; + + List ancestors; + + try { + ancestors = file.getAncestors(); + } catch (IOException e) { + throw new FacesException(e); + } + + ReportFile thisFile = getObject(); + + if (file.equals(thisFile)) { + selectedNode = this; + } else if (ancestors.contains(thisFile)) { + for (TreeNode node : getChildren()) { + RepositoryNode fileNode = (RepositoryNode) node; + + selectedNode = fileNode.findNode(file); + + if (selectedNode != null) { + break; + } + } + } + + return selectedNode; + } + + /** + * @param viewId + */ + public RepositoryNode findNode(String viewId) { + if (viewId == null) { + throw new NullArgumentException("viewId"); + } + + RepositoryNode selectedNode = null; + + if (viewId.equals(this.viewId)) { + selectedNode = this; + } else if (isLoaded()) { + for (TreeNode node : getChildren()) { + RepositoryNode fileNode = (RepositoryNode) node; + + selectedNode = fileNode.findNode(viewId); + + if (selectedNode != null) { + break; + } + } + } + + return selectedNode; + } + + /** + * @see javax.faces.component.StateHolder#isTransient() + */ + @Override + public boolean isTransient() { + return transientState; + } + + /** + * @see javax.faces.component.StateHolder#setTransient(boolean) + */ + @Override + public void setTransient(boolean newTransientValue) { + this.transientState = newTransientValue; + } + + /** + * @see + * javax.faces.component.StateHolder#saveState(javax.faces.context.FacesContext) + */ + @Override + public Object saveState(FacesContext context) { + List states = new LinkedList(); + + states.add(isSelectable()); + states.add(isSelected()); + states.add(isExpanded()); + states.add(viewId); + states.add(getObject().getPath()); + + if (filter instanceof Serializable) { + states.add(filter); + } + + return states.toArray(new Object[states.size()]); + } + + /** + * @see + * javax.faces.component.StateHolder#restoreState(javax.faces.context.FacesContext, + * java.lang.Object) + */ + @Override + public void restoreState(FacesContext context, Object state) { + Object[] states = (Object[]) state; + + if (repository == null) { + Application application = context.getApplication(); + this.repository = application.evaluateExpressionGet(context, + "#{reportRepository}", ReportRepository.class); + } + + try { + setObject(repository.getFile((String) states[4])); + } catch (IOException e) { + throw new FacesException(e); + } + + setSelectable((Boolean) states[0]); + setSelected((Boolean) states[1]); + setExpanded((Boolean) states[2]); + setViewId((String) states[3]); + + if (states.length > 5) { + this.filter = (RepositoryFileFilter) states[5]; + } + } + + /** + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + return new HashCodeBuilder().append(getObject()).append(repository) + .toHashCode(); + } + + /** + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null) { + return false; + } + + if (getClass() != obj.getClass()) { + return false; + } + + RepositoryNode other = (RepositoryNode) obj; + + return new EqualsBuilder().append(getObject(), other.getObject()) + .append(repository, other.repository).isEquals(); + } + + /** + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return getObject().toString(); + } } diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/SelectionNode.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/SelectionNode.java index 024c428b..f6eda961 100644 --- a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/SelectionNode.java +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/ui/navigator/SelectionNode.java @@ -10,113 +10,113 @@ public class SelectionNode extends MetadataNode { - private MemberSelection selection; - - private TreeNode node; - - /** - * @param selection - */ - public SelectionNode(MemberSelection selection) { - this(selection, selection); - } - - /** - * @param node - * @param selection - */ - SelectionNode(TreeNode node, MemberSelection selection) { - super(node.getReference()); - - this.node = node; - this.selection = selection; - - boolean selected = selection.isSelected(node.getReference()); - - setSelectable(true); - setExpanded(true); - - NodeData data = getData(); - if (data != null) { - data.setSelected(selected); - } - } - - /** - * @see org.primefaces.model.TreeNode#getType() - */ - @Override - public String getType() { - return "member"; - } - - /** - * @see org.primefaces.model.TreeNode#getChildCount() - */ - @Override - public int getChildCount() { - return node.getChildCount(); - } - - /** - * @see org.primefaces.model.TreeNode#isLeaf() - */ - @Override - public boolean isLeaf() { - return getChildCount() == 0; - } - - /** - * @param child - */ - public void moveUp(SelectionNode child) { - int index = getChildren().indexOf(child); - - if (index < 0) { - throw new IllegalArgumentException( - "The specified node is not a child of this node."); - } - - SelectionNode other = (SelectionNode) getChildren().get(index - 1); - - getChildren().set(index, other); - getChildren().set(index - 1, child); - } - - /** - * @param child - */ - public void moveDown(SelectionNode child) { - int index = getChildren().indexOf(child); - - if (index < 0) { - throw new IllegalArgumentException( - "The specified node is not a child of this node."); - } - - SelectionNode other = (SelectionNode) getChildren().get(index + 1); - - getChildren().set(index, other); - getChildren().set(index + 1, child); - } - - /** - * @see org.pivot4j.analytics.ui.navigator.MetadataNode#createChildren() - */ - @Override - protected List createChildren() { - List> nodes = node.getChildren(); - - List children = new ArrayList( - nodes.size()); - - for (TreeNode memberNode : nodes) { - SelectionNode child = new SelectionNode(memberNode, selection); - child.setParent(this); - - children.add(child); - } - - return children; - } -} \ No newline at end of file + private MemberSelection selection; + + private TreeNode node; + + /** + * @param selection + */ + public SelectionNode(MemberSelection selection) { + this(selection, selection); + } + + /** + * @param node + * @param selection + */ + SelectionNode(TreeNode node, MemberSelection selection) { + super(node.getReference()); + + this.node = node; + this.selection = selection; + + boolean selected = selection.isSelected(node.getReference()); + + setSelectable(true); + setExpanded(true); + + NodeData data = getData(); + if (data != null) { + data.setSelected(selected); + } + } + + /** + * @see org.primefaces.model.TreeNode#getType() + */ + @Override + public String getType() { + return "member"; + } + + /** + * @see org.primefaces.model.TreeNode#getChildCount() + */ + @Override + public int getChildCount() { + return node.getChildCount(); + } + + /** + * @see org.primefaces.model.TreeNode#isLeaf() + */ + @Override + public boolean isLeaf() { + return getChildCount() == 0; + } + + /** + * @param child + */ + public void moveUp(SelectionNode child) { + int index = getChildren().indexOf(child); + + if (index < 0) { + throw new IllegalArgumentException( + "The specified node is not a child of this node."); + } + + SelectionNode other = (SelectionNode) getChildren().get(index - 1); + + getChildren().set(index, other); + getChildren().set(index - 1, child); + } + + /** + * @param child + */ + public void moveDown(SelectionNode child) { + int index = getChildren().indexOf(child); + + if (index < 0) { + throw new IllegalArgumentException( + "The specified node is not a child of this node."); + } + + SelectionNode other = (SelectionNode) getChildren().get(index + 1); + + getChildren().set(index, other); + getChildren().set(index + 1, child); + } + + /** + * @see org.pivot4j.analytics.ui.navigator.MetadataNode#createChildren() + */ + @Override + protected List createChildren() { + List> nodes = node.getChildren(); + + List children = new ArrayList( + nodes.size()); + + for (TreeNode memberNode : nodes) { + SelectionNode child = new SelectionNode(memberNode, selection); + child.setParent(this); + + children.add(child); + } + + return children; + } +} diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/util/CORSFilter.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/util/CORSFilter.java new file mode 100644 index 00000000..34a1fb15 --- /dev/null +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/util/CORSFilter.java @@ -0,0 +1,72 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.pivot4j.analytics.util; + +import java.io.IOException; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * + * @author jjunior + */ +public class CORSFilter implements Filter { + + /** + * Default constructor. + */ + public CORSFilter() { + // TODO Auto-generated constructor stub + } + + /** + * @see Filter#destroy() + */ + public void destroy() { + // TODO Auto-generated method stub + } + + /** + * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain) + */ + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) + throws IOException, ServletException { + + HttpServletRequest request = (HttpServletRequest) servletRequest; + //System.out.println("CORSFilter HTTP Request: " + request.getMethod()); + + // Authorize (allow) all domains to consume the content + ((HttpServletResponse) servletResponse).addHeader("Access-Control-Allow-Origin", "*"); + ((HttpServletResponse) servletResponse).addHeader("Access-Control-Allow-Methods", "GET, OPTIONS, HEAD, PUT, POST"); + ((HttpServletResponse) servletResponse).setCharacterEncoding("UTF-8"); + + HttpServletResponse resp = (HttpServletResponse) servletResponse; + + // For HTTP OPTIONS verb/method reply with ACCEPTED status code -- per CORS handshake + if (request.getMethod().equals("OPTIONS")) { + resp.setStatus(HttpServletResponse.SC_ACCEPTED); + return; + } + + // pass the request along the filter chain + chain.doFilter(request, servletResponse); + } + + /** + * @see Filter#init(FilterConfig) + */ + public void init(FilterConfig fConfig) throws ServletException { + // TODO Auto-generated method stub + } + +} diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/util/Dsp.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/util/Dsp.java new file mode 100644 index 00000000..bc8502fe --- /dev/null +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/util/Dsp.java @@ -0,0 +1,66 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.pivot4j.analytics.util; + +import java.io.InputStream; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import mondrian.i18n.LocalizingDynamicSchemaProcessor; +import mondrian.olap.Util; +import mondrian.spi.DynamicSchemaProcessor; + +/** + * + * @author jjunior + */ +public class Dsp extends LocalizingDynamicSchemaProcessor implements DynamicSchemaProcessor { + + @Override + public String filter(String schemaUrl, Util.PropertyList connectInfo, InputStream stream) throws Exception { + + String credor = null; + + try { + credor = new DspCredor().getCredor(); + } catch (Exception e) { + e.printStackTrace(); + } + + String schema = super.filter(schemaUrl, connectInfo, stream); + + try { + schema = schema.replaceAll("%CREDOR%", credor); + } catch (Exception e) { + schema = schema.replaceAll("%CREDOR%", "0"); + } + + return schema; + } + + /** + * Replaces the SECURITY_PATTERN clause in the given schema + */ + String replaceSecurityPattern(String schema, String credor) { + + Matcher matcher = Pattern.compile("=$CREDOR").matcher(schema); + StringBuffer sb = new StringBuffer(); + if (credor != null && !credor.isEmpty()) { + while (matcher.find()) { + matcher.appendReplacement(sb, credor); + } + return matcher.appendTail(sb).toString(); + } else { + while (matcher.find()) { + matcher.appendReplacement(sb, " IS NOT NULL"); + } + return matcher.appendTail(sb).toString(); +// return schema.replaceAll("=$CREDOR", " IS NOT NULL"); + + } + + } + +} diff --git a/pivot4j-analytics/src/main/java/org/pivot4j/analytics/util/DspCredor.java b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/util/DspCredor.java new file mode 100644 index 00000000..18166ab6 --- /dev/null +++ b/pivot4j-analytics/src/main/java/org/pivot4j/analytics/util/DspCredor.java @@ -0,0 +1,45 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.pivot4j.analytics.util; + +import java.io.Serializable; +import javax.faces.context.FacesContext; +import javax.servlet.http.HttpSession; + +/** + * + * @author jjunior + */ +public class DspCredor implements Serializable { + + HttpSession session = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(false); + + private String credor; + + public DspCredor() { + } + + public DspCredor(String credor) { + this.credor = credor; + } + + public String getCredor() { + + try { + credor = (String) session.getAttribute("idCredor"); + } catch (Exception e) { + e.printStackTrace(); + credor = "0"; + } + + return credor; + } + + public void setCredor(String credor) { + this.credor = credor; + } + +} diff --git a/pivot4j-analytics/src/main/resources/META-INF/faces-config.xml b/pivot4j-analytics/src/main/resources/META-INF/faces-config.xml index 3f97651d..2f8fa55d 100644 --- a/pivot4j-analytics/src/main/resources/META-INF/faces-config.xml +++ b/pivot4j-analytics/src/main/resources/META-INF/faces-config.xml @@ -1,5 +1,5 @@ + xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"> diff --git a/pivot4j-analytics/src/main/resources/context.xml b/pivot4j-analytics/src/main/resources/context.xml new file mode 100644 index 00000000..b8edee68 --- /dev/null +++ b/pivot4j-analytics/src/main/resources/context.xml @@ -0,0 +1,6 @@ + + + diff --git a/pivot4j-analytics/src/main/resources/log4j2-test.xml b/pivot4j-analytics/src/main/resources/log4j2-test.xml deleted file mode 100644 index 48b1ca91..00000000 --- a/pivot4j-analytics/src/main/resources/log4j2-test.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/pivot4j-analytics/src/main/resources/log4j2.xml b/pivot4j-analytics/src/main/resources/log4j2.xml new file mode 100644 index 00000000..e42bda73 --- /dev/null +++ b/pivot4j-analytics/src/main/resources/log4j2.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pivot4j-analytics/src/main/resources/mondrian.properties b/pivot4j-analytics/src/main/resources/mondrian.properties index 2e3194dd..3c14f88a 100644 --- a/pivot4j-analytics/src/main/resources/mondrian.properties +++ b/pivot4j-analytics/src/main/resources/mondrian.properties @@ -1,10 +1,26 @@ -# Allow the use of aggregates -mondrian.rolap.aggregates.Use=true -mondrian.rolap.aggregates.Read=true -mondrian.native.topcount.enable=true -mondrian.native.filter.enable=true - -# mondrian.properties -mondrian.result.limit=50000 - -mondrian.rolap.ignoreInvalidMembers=true +# Allow the use of aggregates +mondrian.rolap.aggregates.Use=true +mondrian.rolap.aggregates.Read=true +mondrian.native.topcount.enable=true +mondrian.native.filter.enable=true + +# mondrian.properties +mondrian.result.limit=500000 + +mondrian.rolap.ignoreInvalidMembers=true + +# Caching Parameters +mondrian.expCache.enable=false +mondrian.rolap.EnableRolapCubeMemberCache=false +mondrian.rolap.star.disableCaching=true +mondrian.rolap.star.disableLocalSegmentCache=true + +# Default is true +mondrian.util.memoryMonitor.enable=false + +#Defines how a null Member is represented in the result output. MSAS 2000 shows empty value while MSAS 2005 shows "(null)" +mondrian.olap.NullMemberRepresentation= + +#absolute - The SOLVE_ORDER value is absolute regardless of where it is defined; e.g. a query defined calculated member with a SOLVE_ORDER of 1 always takes precedence over a cube defined value of 2. +#scoped - Cube calculated members are resolved before any session scope calculated members, and session scope members are resolved before any query defined calculation. The SOLVE_ORDER value only applies within the scope in which it was defined. +mondrian.rolap.SolveOrderMode=scoped \ No newline at end of file diff --git a/pivot4j-analytics/src/main/resources/org/pivot4j/analytics/i18n/messages.properties b/pivot4j-analytics/src/main/resources/org/pivot4j/analytics/i18n/messages.properties index 7b4660ad..dc520deb 100644 --- a/pivot4j-analytics/src/main/resources/org/pivot4j/analytics/i18n/messages.properties +++ b/pivot4j-analytics/src/main/resources/org/pivot4j/analytics/i18n/messages.properties @@ -277,3 +277,15 @@ warn.member.exists.title = Unable to add member warn.noMembers.remove.message = There are no members to remove. warn.noMembers.select.message = There are no members to select. warn.noMembers.title = Note : + +report.title.extension = .pivo4j + +security.logout = Logout +security.login = Login +security.username = Login +security.password = Password +security.title = Please sign in +security.login.error = Your login attempt was not successful due to + +enable.available.themes.parameter = Enable chanhe theme +enable.available.mdx.parameter = Enable panel MDX \ No newline at end of file diff --git a/pivot4j-analytics/src/main/resources/org/pivot4j/analytics/i18n/messages_en.properties b/pivot4j-analytics/src/main/resources/org/pivot4j/analytics/i18n/messages_en.properties index ab9786e6..709567f6 100644 --- a/pivot4j-analytics/src/main/resources/org/pivot4j/analytics/i18n/messages_en.properties +++ b/pivot4j-analytics/src/main/resources/org/pivot4j/analytics/i18n/messages_en.properties @@ -260,6 +260,7 @@ toolbar.spans.show = Show Spans toolbar.spans.tooltip = Show or hide merged cells. toolbar.swap_axes = Swap Axes toolbar.swap_axes.tooltip = Swap the pivot axes with each other. +toolbar.logout = Logout unit.degree = Degrees @@ -277,3 +278,15 @@ warn.member.exists.title = Unable to add member warn.noMembers.remove.message = There are no members to remove. warn.noMembers.select.message = There are no members to select. warn.noMembers.title = Note : + +report.title.extension = .pivo4j + +security.logout = Logout +security.login = Login +security.username = Login +security.password = Password +security.title = Please sign in +security.login.error = Your login attempt was not successful due to + +enable.available.themes.parameter = Enable chanhe theme +enable.available.mdx.parameter = Enable panel MDX \ No newline at end of file diff --git a/pivot4j-analytics/src/main/resources/org/pivot4j/analytics/i18n/messages_fr.properties b/pivot4j-analytics/src/main/resources/org/pivot4j/analytics/i18n/messages_fr.properties index 7c2649c8..c9369425 100644 --- a/pivot4j-analytics/src/main/resources/org/pivot4j/analytics/i18n/messages_fr.properties +++ b/pivot4j-analytics/src/main/resources/org/pivot4j/analytics/i18n/messages_fr.properties @@ -6,60 +6,60 @@ button.cancel = Annuler button.close = Fermer button.down = Descendre button.export = Exporter -button.hierarchyConfig.tooltip = Configurer les membres des hi\u00E9rarchies. +button.hierarchyConfig.tooltip = Configurer les membres des hi\u00e9rarchies. button.no = Non button.ok = Ok button.remove = Supprimer button.removeAll = Tout supprimer -button.reset = R\u00E9initialiser -button.reset.tooltip = R\u00E9initialiser la requ\u00EAte MDX \u00E0 son pr\u00E9cedent \u00E9tat. -button.run = Ex\u00E9cuter -button.run.tooltip = Ex\u00E9cuter la requ\u00EAte MDX. -button.show.settings = Montrer les param\u00E8tres +button.reset = R\u00e9initialiser +button.reset.tooltip = R\u00e9initialiser la requ\u00eate MDX \u00e0 son pr\u00e9cedent \u00e9tat. +button.run = Ex\u00e9cuter +button.run.tooltip = Ex\u00e9cuter la requ\u00eate MDX. +button.show.settings = Montrer les param\u00e8tres button.up = Monter button.yes = Oui -confirm.folder.delete = Supprimer le dossier s\u00E9lectionn\u00E9 et l'ensemble de son contenu ? -confirm.report.close = Le rapport a \u00E9t\u00E9 modifi\u00E9. Voulez-vous enregistrer les modifications ? +confirm.folder.delete = Supprimer le dossier s\u00e9lectionn\u00e9 et l'ensemble de son contenu ? +confirm.report.close = Le rapport a \u00e9t\u00e9 modifi\u00e9. Voulez-vous enregistrer les modifications ? confirm.report.delete = Voulez vous supprimer le rapport ? -error.catalogList.title = Impossible de r\u00E9cup\u00E9rer la liste des catalogues -error.create.folder.io = Impossible de cr\u00E9er un nouveau dossier : -error.create.folder.title = Impossible de cr\u00E9er un dossier -error.cubeList.title = Impossible de r\u00E9cup\u00E9rer la liste des cubes +error.catalogList.title = Impossible de r\u00e9cup\u00e9rer la liste des catalogues +error.create.folder.io = Impossible de cr\u00e9er un nouveau dossier : +error.create.folder.title = Impossible de cr\u00e9er un dossier +error.cubeList.title = Impossible de r\u00e9cup\u00e9rer la liste des cubes error.delete.folder.message = Impossible de supprimer le dossier : error.delete.folder.title = Impossible de supprimer le dossier error.delete.report.message = Impossible de supprimer le rapport : error.delete.report.title = Impossible de supprimer le rapport -error.execute.title = Impossible d'ex\u00E9cuter la requ\u00EAte MDX -error.filter.message = La hi\u00E9rarchie sp\u00E9cifi\u00E9e est d\u00E9j\u00E0 pr\u00E9sente sur l'un des axes. -error.filter.title = Impossible de filtrer la hi\u00E9rarchie -error.open.report.dataSource = Impossible de trouver une source de donn\u00E9e : +error.execute.title = Impossible d'ex\u00e9cuter la requ\u00eate MDX +error.filter.message = La hi\u00e9rarchie sp\u00e9cifi\u00e9e est d\u00e9j\u00e0 pr\u00e9sente sur l'un des axes. +error.filter.title = Impossible de filtrer la hi\u00e9rarchie +error.open.report.dataSource = Impossible de trouver une source de donn\u00e9e : error.open.report.format = Format invalide pour le rapport. error.open.report.io = Impossible d'ouvrir le rapport : error.open.report.title = Impossible d'ouvrir le rapport -error.property.expression.title = Impossible d'\u00E9valuer la propri\u00E9t\u00E9 ''{0}'' +error.property.expression.title = Impossible d'\u00e9valuer la propri\u00e9t\u00e9 ''{0}'' error.save.report.format = Format invalide pour le rapport. error.save.report.io = Impossible d'enregistrer le rapport : error.save.report.title = Impossible d'enregistrer le rapport -error.unhandled.message = Veuillez consulter la log pour plus de d\u00E9tails : -error.unhandled.title = Une exception non g\u00E9r\u00E9e est survenue +error.unhandled.message = Veuillez consulter la log pour plus de d\u00e9tails : +error.unhandled.title = Une exception non g\u00e9r\u00e9e est survenue header.drillThrough.selection = Choix des colonnes -header.editor = Requ\u00EAte MDX -header.grid = R\u00E9sultat de requ\u00EAte +header.editor = Requ\u00eate MDX +header.grid = R\u00e9sultat de requ\u00eate header.hierarchyConfig.members.all = Tous les membres -header.hierarchyConfig.members.selected = Membres s\u00E9lectionn\u00E9s +header.hierarchyConfig.members.selected = Membres s\u00e9lectionn\u00e9s header.navigator.olap = Navigateur OLAP -header.navigator.report = R\u00E9f\u00E9rentiel de rapport -header.pdfExport.contentSettings = Param\u00E9trage du contenu -header.pdfExport.pageSettings = Param\u00E9trage de page +header.navigator.report = R\u00e9f\u00e9rentiel de rapport +header.pdfExport.contentSettings = Param\u00e9trage du contenu +header.pdfExport.pageSettings = Param\u00e9trage de page header.structure.cube = Structure du cube header.structure.pivot = Structure du pivot -label.aggregation.position.grand = Agr\u00E9gation sur les axes -label.aggregation.position.hierarchy = Agr\u00E9gation sur les hi\u00E9rarchies -label.aggregation.position.member = Agr\u00E9gation sur les membres +label.aggregation.position.grand = Agr\u00e9gation sur les axes +label.aggregation.position.hierarchy = Agr\u00e9gation sur les hi\u00e9rarchies +label.aggregation.position.member = Agr\u00e9gation sur les membres label.aggregation.type.AVG = Moyenne label.aggregation.type.CNT = Nb de valeurs label.aggregation.type.MAX = Maximum @@ -70,80 +70,80 @@ label.chart.items.Bar = Graphique en barres label.chart.items.HorizontalBar = Barres horizontals label.chart.items.Line = Graphique en lignes label.chart.items.Pie = Graphique en secteurs -label.chart.items.StackedArea = Graphique en aires empil\u00E9es -label.chart.items.StackedBar = Graphique en barres empil\u00E9es +label.chart.items.StackedArea = Graphique en aires empil\u00e9es +label.chart.items.StackedBar = Graphique en barres empil\u00e9es label.columns = Colonnes label.cube = Cube label.drillThrough.maxRows = Nb de lignes max label.drillThrough.maxRows.info = (0: pas de lilite) label.filter = Filtre -label.mdx = Requ\u00EAte MDX +label.mdx = Requ\u00eate MDX label.name = Nom label.none = Aucun -label.paginator.jumpTo = Aller \u00E0 +label.paginator.jumpTo = Aller \u00e0 label.paginator.pageSize = Taille de page -label.pdfExport.content.font.size = Taille police par d\u00E9faut +label.pdfExport.content.font.size = Taille police par d\u00e9faut label.pdfExport.footer.font.size = Taille police pied de page label.pdfExport.footer.show = Montrer pied de page label.pdfExport.footer.text = Texte pied de page -label.pdfExport.header.font.size = Taille police en-t\u00EAte -label.pdfExport.header.show = Montrer en-t\u00EAte -label.pdfExport.header.text = Texte en-t\u00EAte +label.pdfExport.header.font.size = Taille police en-t\u00eate +label.pdfExport.header.show = Montrer en-t\u00eate +label.pdfExport.header.text = Texte en-t\u00eate label.pdfExport.page.orientation = Orientation page label.pdfExport.page.orientation.landscape = Paysage label.pdfExport.page.orientation.portrait = Portrait label.pdfExport.page.size = Taille de page label.picklist.available = Disponible -label.picklist.selected = S\u00E9lectionn\u00E9 +label.picklist.selected = S\u00e9lectionn\u00e9 label.properties.expression = Expression label.properties.useExpression = utiliser Expression label.properties.useExpression.description = Activer le support des expressions de langue. label.properties.value = Valeur -label.repository = R\u00E9f\u00E9rentiel de rapport +label.repository = R\u00e9f\u00e9rentiel de rapport label.rows = Lignes -label.theme.default = S\u00E9lectionner un th\u00E8me +label.theme.default = S\u00e9lectionner un th\u00e8me label.untitled = Sans Titre({0}) menu.delete = Supprimer -menu.delete.folder.tooltip = Supprimer le dossier s\u00E9lectionn\u00E9. -menu.delete.report.tooltip = Supprimer le rapport s\u00E9lectionn\u00E9. +menu.delete.folder.tooltip = Supprimer le dossier s\u00e9lectionn\u00e9. +menu.delete.report.tooltip = Supprimer le rapport s\u00e9lectionn\u00e9. menu.hierarchyConfig.remove.children = Supprimer les enfants menu.hierarchyConfig.remove.descendants = Supprimer les descendants -menu.hierarchyConfig.remove.siblings = Supprimer les fr\u00E8res et soeurs +menu.hierarchyConfig.remove.siblings = Supprimer les fr\u00e8res et soeurs menu.hierarchyConfig.remove.single = Supprimer membre -menu.hierarchyConfig.select.children = S\u00E9lectionner les enfants -menu.hierarchyConfig.select.descendants = S\u00E9lectionner les descendants -menu.hierarchyConfig.select.siblings = S\u00E9lectionner les fr\u00E8res et soeurs +menu.hierarchyConfig.select.children = S\u00e9lectionner les enfants +menu.hierarchyConfig.select.descendants = S\u00e9lectionner les descendants +menu.hierarchyConfig.select.siblings = S\u00e9lectionner les fr\u00e8res et soeurs menu.hierarchyConfig.select.single = Selectinner membre menu.new.folder = Nouveau dossier -menu.new.folder.tooltip = Cr\u00E9er un nouveau dossier \u00E0 cet emplacement. -menu.refresh = Rafra\u00EEchir -menu.refresh.tooltip = Rafra\u00EEchir le contenu de ce dossier. +menu.new.folder.tooltip = Cr\u00e9er un nouveau dossier \u00e0 cet emplacement. +menu.refresh = Rafra\u00eechir +menu.refresh.tooltip = Rafra\u00eechir le contenu de ce dossier. message.about = Pivot4J Analytics est une application construite avec PrimeFaces pour montrer un usage basique de la librairie Pivot4J. -message.catalog.chooser = Veuillez s\u00E9lectionner un sch\u00E9ma et un cube pour cr\u00E9er un rapport d'analyse. -message.catalog.chooser.default = ---- S\u00E9lectionner un catalogue ---- -message.cubeList.default = ---- S\u00E9lectionner un cube ---- -message.delete.folder.message = Le dossier a bien \u00E9t\u00E9 supprim\u00E9. -message.delete.folder.title = Dossier supprim\u00E9 -message.delete.report.message = Le rapport a bien \u00E9t\u00E9 supprim\u00E9. -message.delete.report.title = Rapport supprim\u00E9 -message.hierarchyConfig.info = S\u00E9lectionner un ou plusieurs membres et cliquer sur le bouton 'Ajouter', ou double-cliquer pour plus d'options. +message.catalog.chooser = Veuillez s\u00e9lectionner un sch\u00e9ma et un cube pour cr\u00e9er un rapport d'analyse. +message.catalog.chooser.default = ---- S\u00e9lectionner un catalogue ---- +message.cubeList.default = ---- S\u00e9lectionner un cube ---- +message.delete.folder.message = Le dossier a bien \u00e9t\u00e9 supprim\u00e9. +message.delete.folder.title = Dossier supprim\u00e9 +message.delete.report.message = Le rapport a bien \u00e9t\u00e9 supprim\u00e9. +message.delete.report.title = Rapport supprim\u00e9 +message.hierarchyConfig.info = S\u00e9lectionner un ou plusieurs membres et cliquer sur le bouton 'Ajouter', ou double-cliquer pour plus d'options. message.loading = Veuillez patienter... -message.noData = Pas de donn\u00E9es disponibles. -message.properties.expr.help.0 = Vous pouvez appuyer sur 'ctrl-space' pour activer l'auto-compl\u00E9tion. -message.properties.expr.help.1 = (Veuillez choisir une propri\u00E9t\u00E9 \u00E0 \u00E9diter) -message.properties.select = Pour les instructions d\u00E9taill\u00E9es sur la syntaxe des expressions, vous r\u00E9f\u00E9rer \u00E0 {0} ici {1}. -message.query.blank = Vous devez au moins placer un niveau ou une mesure en ligne et en colonne pour que la requ\u00EAte soit valide. Vous pouvez placer ces \u00E9l\u00E9ments en les d\u00E9pla\u00E7ant depuis la structure du cube vers les axes de la vue Pivot. -message.query.elapsed = Temps d'ex\u00E9cution de la requ\u00EAte -message.save.report.message = Le rapport a \u00E9t\u00E9 correctement enregistr\u00E9 -message.save.report.title = Rapport enregistr\u00E9 -message.saveAs.report.message = Rapport enregistr\u00E9 : +message.noData = Pas de donn\u00e9es disponibles. +message.properties.expr.help.0 = Vous pouvez appuyer sur 'ctrl-space' pour activer l'auto-compl\u00e9tion. +message.properties.expr.help.1 = (Veuillez choisir une propri\u00e9t\u00e9 \u00e0 \u00e9diter) +message.properties.select = Pour les instructions d\u00e9taill\u00e9es sur la syntaxe des expressions, vous r\u00e9f\u00e9rer \u00e0 {0} ici {1}. +message.query.blank = Vous devez au moins placer un niveau ou une mesure en ligne et en colonne pour que la requ\u00eate soit valide. Vous pouvez placer ces \u00e9l\u00e9ments en les d\u00e9pla\u00e7ant depuis la structure du cube vers les axes de la vue Pivot. +message.query.elapsed = Temps d'ex\u00e9cution de la requ\u00eate +message.save.report.message = Le rapport a \u00e9t\u00e9 correctement enregistr\u00e9 +message.save.report.title = Rapport enregistr\u00e9 +message.saveAs.report.message = Rapport enregistr\u00e9 : properties.bgColor = Couleur de fond properties.bgColor.description = Couleur de fond de la cellule properties.category.Cell = Cellules -properties.category.Header = En-t\u00EAtes +properties.category.Header = En-t\u00eates properties.category.color = Couleur properties.category.font = Police properties.fgColor = Couleur avant-plan @@ -158,10 +158,10 @@ properties.fontStyle.option.bold = Gras properties.fontStyle.option.bolditalic = Gras, Italique properties.fontStyle.option.italic = Italique properties.fontStyle.option.normal = Normal -properties.label = Intitul\u00E9 -properties.label.description = Intitul\u00E9 de la cellule +properties.label = Intitul\u00e9 +properties.label.description = Intitul\u00e9 de la cellule properties.link = Lien -properties.link.description = Lien URL \u00E0 suivre lorsque l'intitul\u00E9 est cliqu\u00E9 +properties.link.description = Lien URL \u00e0 suivre lorsque l'intitul\u00e9 est cliqu\u00e9 properties.styleClass = Classe stylistique properties.styleClass.description = Classe CSS pour la cellule @@ -169,29 +169,29 @@ title = Application exemple Pivot4J title.about = A propos title.about.welcome = Bienvenue dans Pivot4J Analytics ! -title.aggregation = Configuration de l'agr\u00E9gation +title.aggregation = Configuration de l'agr\u00e9gation title.catalog.chooser = Nouveau rapport d'analyse title.confirm = Confirmer -title.drillthrough = R\u00E9sultat du Drill Through +title.drillthrough = R\u00e9sultat du Drill Through title.export.pdf = Export PDF -title.hierarchyConfig = Configuration des hi\u00E9rarchies -title.new.folder = Cr\u00E9er un nouveau dossier -title.properties = Propri\u00E9t\u00E9s +title.hierarchyConfig = Configuration des hi\u00e9rarchies +title.new.folder = Cr\u00e9er un nouveau dossier +title.properties = Propri\u00e9t\u00e9s title.save.report = Enregistrer le rapport toolbar.about = A propos -toolbar.about.tooltip = Afficher des informations compl\u00E9mentaires. +toolbar.about.tooltip = Afficher des informations compl\u00e9mentaires. toolbar.aggregation = Agr. -toolbar.aggregation.tooltip = Ajouter des cellules agr\u00E9g\u00E9es au r\u00E9sultat. +toolbar.aggregation.tooltip = Ajouter des cellules agr\u00e9g\u00e9es au r\u00e9sultat. toolbar.delete = Supprimer toolbar.delete.tooltip = Supprimer le rapport actuel. toolbar.drill = Drill toolbar.drill.member = Membre -toolbar.drill.member.tooltip = Drill down sur sur toutes les positions du membre s\u00E9lectionn\u00E9. +toolbar.drill.member.tooltip = Drill down sur sur toutes les positions du membre s\u00e9lectionn\u00e9. toolbar.drill.position = Position -toolbar.drill.position.tooltip = Drill down sur la position du membre s\u00E9lectionn\u00E9. +toolbar.drill.position.tooltip = Drill down sur la position du membre s\u00e9lectionn\u00e9. toolbar.drill.replace = Replace -toolbar.drill.replace.tooltip = Drill down sur la position s\u00E9lectionn\u00E9e en rempla\u00E7ant le membre courant. +toolbar.drill.replace.tooltip = Drill down sur la position s\u00e9lectionn\u00e9e en rempla\u00e7ant le membre courant. toolbar.drill.through = Through toolbar.drill.through.tooltip = Activer le drill through sur les cellules. toolbar.export = Exporter @@ -203,42 +203,43 @@ toolbar.links.forum = Forum de discussion toolbar.links.home = Page d'accueil toolbar.links.project = Projet GitHub toolbar.new = Nouveau -toolbar.new.tooltip = Cr\u00E9er un nouveau rapport. +toolbar.new.tooltip = Cr\u00e9er un nouveau rapport. toolbar.nonEmpty = Non vide toolbar.nonEmpty.tooltip = Montrer seulement les cellules avec des valeurs non vides. toolbar.open = Ouvrir -toolbar.open.tooltip = Ouvrir le rapport s\u00E9lectionn\u00E9. +toolbar.open.tooltip = Ouvrir le rapport s\u00e9lectionn\u00e9. toolbar.parent.hide = Masque parent toolbar.parent.show = Afficher parent toolbar.parent.tooltip = Afficher ou masquer un membre parent pour chaque cellule. toolbar.print = Imprimer toolbar.print.tooltip = Imprimer cette grille. -toolbar.properties = Propri\u00E9t\u00E9s -toolbar.properties.tooltip = Modifier les propri\u00E9t\u00E9s de la grille. -toolbar.refresh = Rafra\u00EEchir -toolbar.refresh.tooltip = Rafra\u00EEchir le rapport en cours. +toolbar.properties = Propri\u00e9t\u00e9s +toolbar.properties.tooltip = Modifier les propri\u00e9t\u00e9s de la grille. +toolbar.refresh = Rafra\u00eechir +toolbar.refresh.tooltip = Rafra\u00eechir le rapport en cours. toolbar.save = Enregistrer toolbar.save.tooltip = Enregistrer le rapport en cours. toolbar.saveAs = Enregistrer sous -toolbar.saveAs.tooltip = Enregistrer le rapport en cours avec un nom diff\u00E9rent. +toolbar.saveAs.tooltip = Enregistrer le rapport en cours avec un nom diff\u00e9rent. toolbar.scenario = Scenario -toolbar.scenario.tooltip = D\u00E9marrer un nouveau sc\u00E9nario de requ\u00EAte. +toolbar.scenario.tooltip = D\u00e9marrer un nouveau sc\u00e9nario de requ\u00eate. toolbar.spans.hide = Masquer spans toolbar.spans.show = Afficher spans -toolbar.spans.tooltip = Afficher ou masquer cellules fusionn\u00E9es. +toolbar.spans.tooltip = Afficher ou masquer cellules fusionn\u00e9es. toolbar.swap_axes = Interchanger les axes toolbar.swap_axes.tooltip = Interchanger les axes l'un avec l'autre. +toolbar.logout = D\u00e9connexion warn.chart.axis.unused.title = Note : -warn.folder.delete.openReport.message = Le dossier ne peut pas \u00EAtre supprim\u00E9 car il contient un rapport actuellement ouvert. +warn.folder.delete.openReport.message = Le dossier ne peut pas \u00eatre supprim\u00e9 car il contient un rapport actuellement ouvert. warn.folder.delete.title = Impossible de supprimer le dossier -warn.folder.exists = Un fichier ou un dossier avec ce nom est d\u00E9j\u00E0 pr\u00E9sent. -warn.hierarchy.exists.message = La hi\u00E9rarchies s\u00E9lectionn\u00E9e existe d\u00E9j\u00E0 sur l'axe '%s'. -warn.hierarchy.exists.title = Impossible d'ajouter la hi\u00E9rarchie -warn.level.exists.message = La hi\u00E9rarchie du niveau s\u00E9lectionn\u00E9 existe d\u00E9j\u00E0 sur l'axe '%s'. +warn.folder.exists = Un fichier ou un dossier avec ce nom est d\u00e9j\u00e0 pr\u00e9sent. +warn.hierarchy.exists.message = La hi\u00e9rarchies s\u00e9lectionn\u00e9e existe d\u00e9j\u00e0 sur l'axe '%s'. +warn.hierarchy.exists.title = Impossible d'ajouter la hi\u00e9rarchie +warn.level.exists.message = La hi\u00e9rarchie du niveau s\u00e9lectionn\u00e9 existe d\u00e9j\u00e0 sur l'axe '%s'. warn.level.exists.title = Impossible d'ajouter le niveau -warn.member.exists.message = La hi\u00E9rarchie du membre s\u00E9lectionn\u00E9 existe d\u00E9j\u00E0 sur l'axe '%s'. +warn.member.exists.message = La hi\u00e9rarchie du membre s\u00e9lectionn\u00e9 existe d\u00e9j\u00e0 sur l'axe '%s'. warn.member.exists.title = Impossible d'ajouter le membre -warn.noMembers.remove.message = Il n'y a pas de membres \u00E0 retirer. -warn.noMembers.select.message = Il n'y a pas de membres \u00E0 s\u00E9lectionner. +warn.noMembers.remove.message = Il n'y a pas de membres \u00e0 retirer. +warn.noMembers.select.message = Il n'y a pas de membres \u00e0 s\u00e9lectionner. warn.noMembers.title = Note : diff --git a/pivot4j-analytics/src/main/resources/org/pivot4j/analytics/i18n/messages_pt_BR.properties b/pivot4j-analytics/src/main/resources/org/pivot4j/analytics/i18n/messages_pt_BR.properties index 656713bf..4a1db340 100644 --- a/pivot4j-analytics/src/main/resources/org/pivot4j/analytics/i18n/messages_pt_BR.properties +++ b/pivot4j-analytics/src/main/resources/org/pivot4j/analytics/i18n/messages_pt_BR.properties @@ -1,244 +1,279 @@ -#Generated by ResourceBundle Editor (http://eclipse-rbe.sourceforge.net) -# Free contribution from Professor Coruja Team and IT4biz (www.it4biz.com.br and http://blog.professorcoruja.com) -# If you want to help us please send an e-mail to info@it4biz.com.br -# Contributors: -# IT4biz and Professor Coruja Team -# - Caio Moreno de Souza (caio@it4biz.com.br) -# - Maiara Lemos (maiara.lemos@it4biz.com.br) -# - Fernando Maia (fernando.maia@it4biz.com.br) -# Updated on Aug, 30, 2013 - -button.add = Adicionar -button.addAll = Adicionar Todos -button.apply = Aplicar -button.cancel = Cancelar -button.close = Fechar -button.down = Minimizar -button.export = Exportar -button.hierarchyConfig.tooltip = Configurar hierarquia de membros -button.no = N\u00E3o -button.ok = Ok -button.remove = Remover -button.removeAll = Remove tudo -button.reset = Restabelecer -button.reset.tooltip = Restabelecer consulta MDX modificada para o \u00FAltimo estado. -button.run = Rodar -button.run.tooltip = Rodar a atual consulta MDX. -button.show.settings = Mostrar Configura\u00E7\u00F5es -button.up = Maximizar -button.yes = Sim - -confirm.folder.delete = Excluir a pasta selecionada e todo o seu conte\u00FAdo? -confirm.report.close = O relat\u00F3rio foi alterado. Deseja salvar as modifica\u00E7\u00F5es? -confirm.report.delete = Deseja excluir o relat\u00F3rio? - -error.catalogList.title = Falha ao recuperar a lista de cat\u00E1logo -error.create.folder.io = N\u00E3o \u00E9 poss\u00EDvel criar uma nova pasta : -error.create.folder.title = N\u00E3o \u00E9 poss\u00EDvel criar uma pasta -error.cubeList.title = Falha ao recuperar a lista de cubo -error.delete.folder.message = N\u00E3o \u00E9 poss\u00EDvel deletar a pasta : -error.delete.folder.title = N\u00E3o \u00E9 poss\u00EDvel deletar a pasta -error.delete.report.message = N\u00E3o \u00E9 poss\u00EDvel deletar o relat\u00F3rio : -error.delete.report.title = N\u00E3o \u00E9 poss\u00EDvel deletar o relat\u00F3rio -error.execute.title = Falha ao executar consulta MDX -error.filter.message = A hierarquia especificada j\u00E1 est\u00E1 presente em um dos eixos -error.filter.title = Incapaz de filtrar hierarquia -error.open.report.dataSource = N\u00E3o foi poss\u00EDvel encontrar um data source : -error.open.report.format = Detectado inv\u00E1lido formato de arquivo de relat\u00F3rio. -error.open.report.io = N\u00E3o foi poss\u00EDvel abrir o arquivo de relat\u00F3rio: -error.open.report.title = N\u00E3o foi poss\u00EDvel abrir o relat\u00F3rio -error.property.expression.title = N\u00E3o foi poss\u00EDvel avaliar a propriedade ''{0}'' -error.save.report.format = Detectado inv\u00E1lido formato de arquivo de relat\u00F3rio. -error.save.report.io = N\u00E3o foi poss\u00EDvel salvar o relat\u00F3rio : -error.save.report.title = N\u00E3o foi poss\u00EDvel salvar o relat\u00F3rio -error.unhandled.message = Por favor, veja o log para mais detalhes : -error.unhandled.title = Ocorreu uma exce\u00E7\u00E3o n\u00E3o trat\u00E1vel - -header.drillThrough.selection = Sele\u00E7\u00E3o de Coluna -header.editor = Consulta MDX -header.grid = Resultado da Consulta -header.hierarchyConfig.members.all = Todos os Membros -header.hierarchyConfig.members.selected = Selecionar Membros -header.navigator.olap = Navegador OLAP -header.navigator.report = Reposit\u00F3rio de Relat\u00F3rio -header.pdfExport.contentSettings = Configura\u00E7\u00F5es de Conte\u00FAdo -header.pdfExport.pageSettings = Configura\u00E7\u00F5es da P\u00E1gina -header.structure.cube = Estrutura do Cubo -header.structure.pivot = Estrutura Pivot - -label.aggregation.position.grand = Agrega\u00E7\u00E3o de Eixo -label.aggregation.position.hierarchy = Agrega\u00E7\u00E3o de Hierarquia -label.aggregation.position.member = Agrega\u00E7\u00E3o de Membro -label.aggregation.type.AVG = M\u00E9dia -label.aggregation.type.CNT = Contar -label.aggregation.type.MAX = M\u00E1ximo -label.aggregation.type.MIN = M\u00EDnimo -label.aggregation.type.SUM = Total -label.catalog = Cat\u00E1logo -label.columns = Colunas -label.cube = Cubo -label.drillThrough.maxRows = Max. Linhas -label.drillThrough.maxRows.info = (0: Ilimitado) -label.filter = Filtro -label.mdx = Consulta MDX / MDX query -label.name = Nome -label.none = Nenhum -label.paginator.jumpTo = Ir para -label.paginator.pageSize = Tamanho da P\u00E1gina -label.pdfExport.content.font.size = Tamanho da Fonte Padr\u00E3o -label.pdfExport.footer.font.size = Tamanho da Fonte Rodap\u00E9 -label.pdfExport.footer.show = Mostrar Rodap\u00E9 -label.pdfExport.footer.text = Texto Rodap\u00E9 -label.pdfExport.header.font.size = Tamanho da Fonte Cabe\u00E7alho -label.pdfExport.header.show = Mostrar Cabe\u00E7alho -label.pdfExport.header.text = Texto Cabe\u00E7alho -label.pdfExport.page.orientation = Orienta\u00E7\u00E3o da P\u00E1gina -label.pdfExport.page.orientation.landscape = Paisagem -label.pdfExport.page.orientation.portrait = Retrato -label.pdfExport.page.size = Tamanho da P\u00E1gina -label.picklist.available = Dispon\u00EDvel -label.picklist.selected = Selecionado -label.properties.expression = Express\u00E3o -label.properties.useExpression = Usar Express\u00E3o -label.properties.useExpression.description = Ativar o suporte \u00E0 linguagem de express\u00E3o. -label.properties.value = Valor -label.repository = Reposit\u00F3rio de Relat\u00F3rio -label.rows = Linhas -label.theme.default = Escolher tema -label.untitled = Sem T\u00EDtulo({0}) - -menu.delete = Deletar -menu.delete.folder.tooltip = Deletar pastas selecionadas. -menu.delete.report.tooltip = Deletar relat\u00F3rios selecionados. -menu.hierarchyConfig.remove.children = Remover filhos -menu.hierarchyConfig.remove.descendants = Remover descendentes -menu.hierarchyConfig.remove.siblings = Remover irm\u00E3os -menu.hierarchyConfig.remove.single = Remover membros -menu.hierarchyConfig.select.children = Selecionar filhos -menu.hierarchyConfig.select.descendants = Selecionar descendentes -menu.hierarchyConfig.select.siblings = Selecionar irm\u00E3os -menu.hierarchyConfig.select.single = Selecionar membros -menu.new.folder = Nova Pasta -menu.new.folder.tooltip = Criar uma nova pasta sob este local. -menu.refresh = Atualizar -menu.refresh.tooltip = Atualizar conte\u00FAdo desta pasta. - -message.about = Pivot4J Analytics \u00E9 um exemplo de aplicativo constru\u00EDdo com PrimeFaces para mostrar o uso b\u00E1sico da biblioteca Pivot4J. -message.catalog.chooser = Por favor, selecione um Esquema (Schema) e um Cubo (Cube) para criar um relat\u00F3rio de an\u00E1lise. -message.catalog.chooser.default = (Por favor, selecione um cat\u00E1logo) -message.cubeList.default = (Por favor, selecione um cubo) -message.delete.folder.message = A pasta foi deletada com sucesso. -message.delete.folder.title = Pasta deletada -message.delete.report.message = O relat\u00F3rio foi deletado com sucesso. -message.delete.report.title = Relat\u00F3rio deletado. -message.hierarchyConfig.info = Selecione um ou mais membros e pressione o bot\u00E3o \u2018Adicionar\u2019, ou d\u00EA um clique com o bot\u00E3o direito do mouse para ver mais op\u00E7\u00F5es. -message.loading = Por favor, aguarde... -message.noData = N\u00E3o h\u00E1 dados dispon\u00EDveis. -message.properties.expr.help.0 = Pressione 'ctrl-espa\u00E7o' para ativar o auto- preenchimento. -message.properties.expr.help.1 = Para obter instru\u00E7\u00F5es detalhadas sobre a sintaxe de express\u00F5es, consulte {0}aqui{1}. -message.properties.select = (Por favor, selecione uma propriedade para editar) -message.query.blank = Voc\u00EA precisa colocar pelo menos um n\u00EDvel ou m\u00E9trica nas Colunas e Linhas para validar a consulta. Voc\u00EA pode arrastar elementos da estrutura do cubo e solt\u00E1-los em ambos os eixos da janela da estrutura pivot. -message.query.elapsed = Tempo de execu\u00E7\u00E3o da Consulta -message.save.report.message = Relat\u00F3rio salvo com sucesso. -message.save.report.title = Relat\u00F3rio salvo -message.saveAs.report.message = Relat\u00F3rio salvo : - -properties.bgColor = Cor de fundo -properties.bgColor.description = Cor de fundo da c\u00E9lula -properties.category.Cell = C\u00E9lulas -properties.category.Header = Cabe\u00E7alhos -properties.category.color = Cor -properties.category.font = Fonte -properties.fgColor = Cor do primeiro plano -properties.fgColor.description = Cor de primeiro plano da c\u00E9lula -properties.fontFamily = Fam\u00EDlia de Fontes -properties.fontFamily.description = Font family of the cell text -properties.fontSize = Tamanho da Fonte -properties.fontSize.description = Tamanho da Fonte do texto da c\u00E9lula -properties.fontStyle = Estilo da Fonte -properties.fontStyle.description = Estilo do texto da c\u00E9lula (i.e. espessura, obliquidade) -properties.fontStyle.option.bold = Negrito -properties.fontStyle.option.bolditalic = Negrito it\u00E1lico -properties.fontStyle.option.italic = It\u00E1lico -properties.fontStyle.option.normal = Normal -properties.label = R\u00F3tulo -properties.label.description = Texto do r\u00F3tulo da c\u00E9lula -properties.link = Link -properties.link.description = URL do link a seguir quando o r\u00F3tulo \u00E9 clicado -properties.styleClass = Classe de Estilo -properties.styleClass.description = Classe de estilo CSS para o elemento celular - -title = Aplicativo de exemplo Pivot4J - -title.about = Sobre esta Aplica\u00E7\u00E3o -title.about.welcome = Bem- vindo ao aplicativo Pivot4J Analytics! -title.aggregation = Configura\u00E7\u00E3o de Agrega\u00E7\u00E3o -title.catalog.chooser = Novo Relat\u00F3rio Anal\u00EDtico -title.confirm = Confirmar -title.drillthrough = Drill Through pelo Resultado -title.export.pdf = Exportar para PDF -title.hierarchyConfig = Configura\u00E7\u00E3o de Hierarquia -title.new.folder = Criar Nova Pasta -title.properties = Propriedades -title.save.report = Salvar Relat\u00F3rio - -toolbar.about = Sobre -toolbar.about.tooltip = Mostrar informa\u00E7\u00F5es adicionais sobre a aplica\u00E7\u00E3o. -toolbar.aggregation = Agg. -toolbar.aggregation.tooltip = Adicionar c\u00E9lulas agregadas ao resultado. -toolbar.delete = Deletar -toolbar.delete.tooltip = Deletar o atual relat\u00F3rio. -toolbar.drill = Drill -toolbar.drill.member = Membro -toolbar.drill.member.tooltip = Drill Down no membro selecionado em todas as posi\u00E7\u00F5es. -toolbar.drill.position = Drill Posi\u00E7\u00E3o -toolbar.drill.position.tooltip = Drill Down na posi\u00E7\u00E3o do membro selecionado. -toolbar.drill.replace = Substituir -toolbar.drill.replace.tooltip = Drill down na posi\u00E7\u00E3o selecionada substituindo a atual. -toolbar.drill.through = Atrav\u00E9s -toolbar.drill.through.tooltip = Habilitar drill through nas c\u00E9lulas. -toolbar.export = Exportar -toolbar.export.format.pdf = PDF(.pdf) -toolbar.export.format.xls = Microsoft Excel(.xls) -toolbar.export.format.xlsx = Microsoft Excel(.xlsx) -toolbar.links = Links -toolbar.links.forum = F\u00F3rum de Discuss\u00E3o -toolbar.links.home = Home Page -toolbar.links.project = P\u00E1gina do projeto no GitHub -toolbar.new = Novo -toolbar.new.tooltip = Criar novo relat\u00F3rio. -toolbar.nonEmpty = N\u00E3o Vazio -toolbar.nonEmpty.tooltip = Mostrar apenas c\u00E9lulas com valores n\u00E3o vazios. -toolbar.open = Abrir -toolbar.open.tooltip = Abrir o relat\u00F3rio selecionado. -toolbar.parent.hide = Ocultar Pais -toolbar.parent.show = Mostrar Pais -toolbar.parent.tooltip = Mostrar ou ocultar membro pai para cada c\u00E9lula. -toolbar.print = Imprimir -toolbar.print.tooltip = Imprimir esta visualiza\u00E7\u00E3o em grade pivot. -toolbar.properties.tooltip = Editar propriedades da grade pivot. -toolbar.refresh = Atualizar -toolbar.refresh.tooltip = Atualizar atual relat\u00F3rio. -toolbar.save = Salvar -toolbar.save.tooltip = Salvar atual relat\u00F3rio. -toolbar.saveAs = Salvar como -toolbar.saveAs.tooltip = Salvar atual relat\u00F3rio com nome diferente. -toolbar.spans.hide = Ocultar Spans -toolbar.spans.show = Mostrar Span -toolbar.spans.tooltip = Mostrat ou ocultar c\u00E9lulas mescladas. -toolbar.swap_axes = Trocar Eixos -toolbar.swap_axes.tooltip = Trocar os eixos de rota\u00E7\u00E3o com o outro. - -warn.chart.axis.unused.title = Nota : -warn.folder.delete.openReport.message = A pasta n\u00E3o pode ser exclu\u00EDda, pois cont\u00E9m um relat\u00F3rio aberto. -warn.folder.delete.title = N\u00E3o \u00E9 poss\u00EDvel excluir a pasta -warn.folder.exists = J\u00E1 existe um arquivo ou pasta com este nome. -warn.hierarchy.exists.message = A hierarquia selecionada j\u00E1 existe no eixo \u2018%s\u2019. -warn.hierarchy.exists.title = N\u00E3o \u00E9 poss\u00EDvel adicionar hierarquia -warn.level.exists.message = A hierarquia do n\u00EDvel selecionado j\u00E1 existe no eixo '%s'. -warn.level.exists.title = N\u00E3o \u00E9 poss\u00EDvel adicionar n\u00EDvel. -warn.member.exists.message = A hierarquia do membro selecionado j\u00E1 existe no eixo '%s'. -warn.member.exists.title = N\u00E3o \u00E9 poss\u00EDvel adicionar membro -warn.noMembers.remove.message = N\u00E3o h\u00E1 membros a se remover. -warn.noMembers.select.message = N\u00E3o h\u00E1 membros a se selecionar. -warn.noMembers.title = Nota : +#Generated by ResourceBundle Editor (http://eclipse-rbe.sourceforge.net) +# Free contribution from Professor Coruja Team and IT4biz (www.it4biz.com.br and http://blog.professorcoruja.com) +# If you want to help us please send an e-mail to info@it4biz.com.br +# Contributors: +# IT4biz and Professor Coruja Team +# - Caio Moreno de Souza (caio@it4biz.com.br) +# - Maiara Lemos (maiara.lemos@it4biz.com.br) +# - Fernando Maia (fernando.maia@it4biz.com.br) +# - Judilson Costa (judilsonjunior@gmail.com) +# Updated on Apr, 05, 2018 + +button.add = Adicionar +button.addAll = Adicionar Todos +button.apply = Aplicar +button.cancel = Cancelar +button.close = Fechar +button.down = Minimizar +button.export = Exportar +button.hierarchyConfig.tooltip = Configurar hierarquia de membros +button.no = N\u00e3o +button.ok = Ok +button.remove = Remover +button.removeAll = Remove tudo +button.reset = Restabelecer +button.reset.tooltip = Restabelecer consulta MDX modificada para o \u00faltimo estado. +button.run = Rodar +button.run.tooltip = Rodar a atual consulta MDX. +button.show.settings = Mostrar Configura\u00e7\u00f5es +button.up = Maximizar +button.yes = Sim + +confirm.folder.delete = Excluir a pasta selecionada e todo o seu conte\u00fado? +confirm.report.close = O relat\u00f3rio foi alterado. Deseja salvar as modifica\u00e7\u00f5es? +confirm.report.delete = Deseja excluir o relat\u00f3rio? + +error.catalogList.title = Falha ao recuperar a lista de cat\u00e1logo +error.create.folder.io = N\u00e3o \u00e9 poss\u00edvel criar uma nova pasta : +error.create.folder.title = N\u00e3o \u00e9 poss\u00edvel criar uma pasta +error.cubeList.title = Falha ao recuperar a lista de cubo +error.delete.folder.message = N\u00e3o \u00e9 poss\u00edvel deletar a pasta : +error.delete.folder.title = N\u00e3o \u00e9 poss\u00edvel deletar a pasta +error.delete.report.message = N\u00e3o \u00e9 poss\u00edvel deletar o relat\u00f3rio : +error.delete.report.title = N\u00e3o \u00e9 poss\u00edvel deletar o relat\u00f3rio +error.execute.title = Falha ao executar consulta MDX +error.filter.message = A hierarquia especificada j\u00e1 est\u00e1 presente em um dos eixos +error.filter.title = Incapaz de filtrar hierarquia +error.open.report.dataSource = N\u00e3o foi poss\u00edvel encontrar um data source : +error.open.report.format = Detectado inv\u00e1lido formato de arquivo de relat\u00f3rio. +error.open.report.io = N\u00e3o foi poss\u00edvel abrir o arquivo de relat\u00f3rio: +error.open.report.title = N\u00e3o foi poss\u00edvel abrir o relat\u00f3rio +error.property.expression.title = N\u00e3o foi poss\u00edvel avaliar a propriedade ''{0}'' +error.save.report.format = Detectado inv\u00e1lido formato de arquivo de relat\u00f3rio. +error.save.report.io = N\u00e3o foi poss\u00edvel salvar o relat\u00f3rio : +error.save.report.title = N\u00e3o foi poss\u00edvel salvar o relat\u00f3rio +error.unhandled.message = Por favor, veja o log para mais detalhes : +error.unhandled.title = Ocorreu uma exce\u00e7\u00e3o n\u00e3o trat\u00e1vel + +header.drillThrough.selection = Sele\u00e7\u00e3o de Coluna +header.editor = Consulta MDX +header.grid = Resultado da Consulta +header.hierarchyConfig.members.all = Todos os Membros +header.hierarchyConfig.members.selected = Selecionar Membros +header.navigator.olap = Navegador de Vis\u00f5es +header.navigator.report = Reposit\u00f3rio de Relat\u00f3rio +header.pdfExport.contentSettings = Configura\u00e7\u00f5es de Conte\u00fado +header.pdfExport.pageSettings = Configura\u00e7\u00f5es da P\u00e1gina +header.structure.cube = Estrutura do Cubo +header.structure.pivot = Estrutura Pivot + +label.aggregation.position.grand = Agrega\u00e7\u00e3o de Eixo +label.aggregation.position.hierarchy = Agrega\u00e7\u00e3o de Hierarquia +label.aggregation.position.member = Agrega\u00e7\u00e3o de Membro +label.aggregation.type.AVG = M\u00e9dia +label.aggregation.type.CNT = Contar +label.aggregation.type.MAX = M\u00e1ximo +label.aggregation.type.MIN = M\u00ednimo +label.aggregation.type.SUM = Total +label.catalog = Cat\u00e1logo +label.chart = Gr\u00e1fico +label.chart.axis.chart = Gr\u00e1fico +label.chart.axis.page = P\u00e1gina +label.chart.axis.plot = Plot +label.chart.axis.series = S\u00e9ries +label.chart.height = Altura +label.chart.items.Bar = Gr\u00e1fico Barra +label.chart.items.HorizontalBar = Gr\u00e1fico Barra Horizontal +label.chart.items.Line = Gr\u00e1fico Linha +label.chart.items.Pie = Gr\u00e1fico Pizza +label.chart.items.StackedArea = Gr\u00e1fico Empilhado \u00c1rea +label.chart.items.StackedBar = Gr\u00e1fico Empilhado Barra +label.chart.label.angle.x = \u00c2ngulo Eixo X +label.chart.label.angle.y = \u00c2ngulo Eixo Y +label.chart.legend.position = Posi\u00e7\u00e3o +label.chart.legend.position.e = Direita +label.chart.legend.position.n = Topo +label.chart.legend.position.s = Fundo +label.chart.legend.position.w = Esquerda +label.chart.width = Largura +label.chart.width.instruction = (0: ajustar ao espa\u00e7o dispon\u00edvel) +label.columns = Colunas +label.cube = Vis\u00e3o +label.drillThrough.maxRows = Max. Linhas +label.drillThrough.maxRows.info = (0: Ilimitado) +label.filter = Filtro +label.mdx = Consulta MDX / MDX query +label.name = Nome +label.none = Nenhum +label.paginator.jumpTo = Ir para +label.paginator.pageSize = Tamanho da P\u00e1gina +label.pdfExport.content.font.size = Tamanho da Fonte Padr\u00e3o +label.pdfExport.footer.font.size = Tamanho da Fonte Rodap\u00e9 +label.pdfExport.footer.show = Mostrar Rodap\u00e9 +label.pdfExport.footer.text = Texto Rodap\u00e9 +label.pdfExport.header.font.size = Tamanho da Fonte Cabe\u00e7alho +label.pdfExport.header.show = Mostrar Cabe\u00e7alho +label.pdfExport.header.text = Texto Cabe\u00e7alho +label.pdfExport.page.orientation = Orienta\u00e7\u00e3o da P\u00e1gina +label.pdfExport.page.orientation.landscape = Paisagem +label.pdfExport.page.orientation.portrait = Retrato +label.pdfExport.page.size = Tamanho da P\u00e1gina +label.picklist.available = Dispon\u00edvel +label.picklist.selected = Selecionado +label.properties.expression = Express\u00e3o +label.properties.useExpression = Usar Express\u00e3o +label.properties.useExpression.description = Ativar o suporte \u00e0 linguagem de express\u00e3o. +label.properties.value = Valor +label.repository = Reposit\u00f3rio de Relat\u00f3rio +label.rows = Linhas +label.theme.default = Escolher tema +label.untitled = Sem T\u00edtulo({0}) + +menu.delete = Deletar +menu.delete.folder.tooltip = Deletar pastas selecionadas. +menu.delete.report.tooltip = Deletar relat\u00f3rios selecionados. +menu.hierarchyConfig.remove.children = Remover filhos +menu.hierarchyConfig.remove.descendants = Remover descendentes +menu.hierarchyConfig.remove.siblings = Remover irm\u00e3os +menu.hierarchyConfig.remove.single = Remover membros +menu.hierarchyConfig.select.children = Selecionar filhos +menu.hierarchyConfig.select.descendants = Selecionar descendentes +menu.hierarchyConfig.select.siblings = Selecionar irm\u00e3os +menu.hierarchyConfig.select.single = Selecionar membros +menu.new.folder = Nova Pasta +menu.new.folder.tooltip = Criar uma nova pasta sob este local. +menu.refresh = Atualizar +menu.refresh.tooltip = Atualizar conte\u00fado desta pasta. + +message.about = Pivot4J Analytics \u00e9 um exemplo de aplicativo constru\u00eddo com PrimeFaces para mostrar o uso b\u00e1sico da biblioteca Pivot4J. +message.catalog.chooser = Por favor, selecione um Esquema (Schema) e um Cubo (Cube) para criar um relat\u00f3rio de an\u00e1lise. +message.catalog.chooser.default = (Por favor, selecione um cat\u00e1logo) +message.cubeList.default = (Por favor, selecione uma vis\u00e3o) +message.delete.folder.message = A pasta foi deletada com sucesso. +message.delete.folder.title = Pasta deletada +message.delete.report.message = O relat\u00f3rio foi deletado com sucesso. +message.delete.report.title = Relat\u00f3rio deletado. +message.hierarchyConfig.info = Selecione um ou mais membros e pressione o bot\u00e3o \u2018Adicionar\u2019, ou d\u00ea um clique com o bot\u00e3o direito do mouse para ver mais op\u00e7\u00f5es. +message.loading = Por favor, aguarde... +message.noData = N\u00e3o h\u00e1 dados dispon\u00edveis. +message.properties.expr.help.0 = Pressione 'ctrl-espa\u00e7o' para ativar o auto- preenchimento. +message.properties.expr.help.1 = Para obter instru\u00e7\u00f5es detalhadas sobre a sintaxe de express\u00f5es, consulte {0}aqui{1}. +message.properties.select = (Por favor, selecione uma propriedade para editar) +message.query.blank = Voc\u00ea precisa colocar pelo menos um n\u00edvel ou m\u00e9trica nas Colunas e Linhas para validar a consulta. Voc\u00ea pode arrastar elementos da estrutura do cubo e solt\u00e1-los em ambos os eixos da janela da estrutura pivot. +message.query.elapsed = Tempo de execu\u00e7\u00e3o da Consulta +message.save.report.message = Relat\u00f3rio salvo com sucesso. +message.save.report.title = Relat\u00f3rio salvo +message.saveAs.report.message = Relat\u00f3rio salvo : + +properties.bgColor = Cor de fundo +properties.bgColor.description = Cor de fundo da c\u00e9lula +properties.category.Cell = C\u00e9lulas +properties.category.Header = Cabe\u00e7alhos +properties.category.color = Cor +properties.category.font = Fonte +properties.fgColor = Cor do primeiro plano +properties.fgColor.description = Cor de primeiro plano da c\u00e9lula +properties.fontFamily = Fam\u00edlia de Fontes +properties.fontFamily.description = Font family of the cell text +properties.fontSize = Tamanho da Fonte +properties.fontSize.description = Tamanho da Fonte do texto da c\u00e9lula +properties.fontStyle = Estilo da Fonte +properties.fontStyle.description = Estilo do texto da c\u00e9lula (i.e. espessura, obliquidade) +properties.fontStyle.option.bold = Negrito +properties.fontStyle.option.bolditalic = Negrito it\u00e1lico +properties.fontStyle.option.italic = It\u00e1lico +properties.fontStyle.option.normal = Normal +properties.label = R\u00f3tulo +properties.label.description = Texto do r\u00f3tulo da c\u00e9lula +properties.link = Link +properties.link.description = URL do link a seguir quando o r\u00f3tulo \u00e9 clicado +properties.styleClass = Classe de Estilo +properties.styleClass.description = Classe de estilo CSS para o elemento celular + +title = Aplicativo de exemplo Pivot4J + +title.about = Sobre esta Aplica\u00e7\u00e3o +title.about.welcome = Bem- vindo ao aplicativo Pivot4J Analytics! +title.aggregation = Configura\u00e7\u00e3o de Agrega\u00e7\u00e3o +title.catalog.chooser = Novo Relat\u00f3rio Anal\u00edtico +title.confirm = Confirmar +title.drillthrough = Drill Through pelo Resultado +title.export.pdf = Exportar para PDF +title.hierarchyConfig = Configura\u00e7\u00e3o de Hierarquia +title.new.folder = Criar Nova Pasta +title.properties = Propriedades +title.save.report = Salvar Relat\u00f3rio + +toolbar.about = Sobre +toolbar.about.tooltip = Mostrar informa\u00e7\u00f5es adicionais sobre a aplica\u00e7\u00e3o. +toolbar.aggregation = Agg. +toolbar.aggregation.tooltip = Adicionar c\u00e9lulas agregadas ao resultado. +toolbar.delete = Deletar +toolbar.delete.tooltip = Deletar o atual relat\u00f3rio. +toolbar.drill = Drill +toolbar.drill.member = Membro +toolbar.drill.member.tooltip = Drill Down no membro selecionado em todas as posi\u00e7\u00f5es. +toolbar.drill.position = Drill Posi\u00e7\u00e3o +toolbar.drill.position.tooltip = Drill Down na posi\u00e7\u00e3o do membro selecionado. +toolbar.drill.replace = Substituir +toolbar.drill.replace.tooltip = Drill down na posi\u00e7\u00e3o selecionada substituindo a atual. +#toolbar.drill.through = Atrav\u00e9s +toolbar.drill.through = Detalhar +toolbar.drill.through.tooltip = Habilitar drill through nas c\u00e9lulas. +toolbar.export = Exportar +toolbar.export.format.pdf = PDF(.pdf) +toolbar.export.format.xls = Microsoft Excel(.xls) +toolbar.export.format.xlsx = Microsoft Excel(.xlsx) +toolbar.links = Links +toolbar.links.forum = F\u00f3rum de Discuss\u00e3o +toolbar.links.home = Home Page +toolbar.links.project = P\u00e1gina do projeto no GitHub +toolbar.new = Novo +toolbar.new.tooltip = Criar novo relat\u00f3rio. +toolbar.nonEmpty = N\u00e3o Vazio +toolbar.nonEmpty.tooltip = Mostrar apenas c\u00e9lulas com valores n\u00e3o vazios. +toolbar.open = Abrir +toolbar.open.tooltip = Abrir o relat\u00f3rio selecionado. +toolbar.parent.hide = Ocultar Pais +toolbar.parent.show = Mostrar Pais +toolbar.parent.tooltip = Mostrar ou ocultar membro pai para cada c\u00e9lula. +toolbar.print = Imprimir +toolbar.print.tooltip = Imprimir esta visualiza\u00e7\u00e3o em grade pivot. +toolbar.properties.tooltip = Editar propriedades da grade pivot. +toolbar.refresh = Atualizar +toolbar.refresh.tooltip = Atualizar atual relat\u00f3rio. +toolbar.save = Salvar +toolbar.save.tooltip = Salvar atual relat\u00f3rio. +toolbar.saveAs = Salvar como +toolbar.saveAs.tooltip = Salvar atual relat\u00f3rio com nome diferente. +toolbar.spans.hide = Ocultar Spans +toolbar.spans.show = Mostrar Span +toolbar.spans.tooltip = Mostrar ou ocultar c\u00e9lulas mescladas. +toolbar.swap_axes = Trocar Eixos +toolbar.swap_axes.tooltip = Trocar os eixos de rota\u00e7\u00e3o com o outro. + +warn.chart.axis.unused.title = Nota : +warn.folder.delete.openReport.message = A pasta n\u00e3o pode ser exclu\u00edda, pois cont\u00e9m um relat\u00f3rio aberto. +warn.folder.delete.title = N\u00e3o \u00e9 poss\u00edvel excluir a pasta +warn.folder.exists = J\u00e1 existe um arquivo ou pasta com este nome. +warn.hierarchy.exists.message = A hierarquia selecionada j\u00e1 existe no eixo \u2018%s\u2019. +warn.hierarchy.exists.title = N\u00e3o \u00e9 poss\u00edvel adicionar hierarquia +warn.level.exists.message = A hierarquia do n\u00edvel selecionado j\u00e1 existe no eixo '%s'. +warn.level.exists.title = N\u00e3o \u00e9 poss\u00edvel adicionar n\u00edvel. +warn.member.exists.message = A hierarquia do membro selecionado j\u00e1 existe no eixo '%s'. +warn.member.exists.title = N\u00e3o \u00e9 poss\u00edvel adicionar membro +warn.noMembers.remove.message = N\u00e3o h\u00e1 membros a se remover. +warn.noMembers.select.message = N\u00e3o h\u00e1 membros a se selecionar. +warn.noMembers.title = Nota : + +report.title.extension = .pivot4j + +security.logout = Sair +security.login = Entrar +security.username = Usu\u00e1rio +security.password = Senha +security.title = Por favor, identifique-se +security.login.error = Sua tentativa de login n\u00e3o foi bem-sucedida devido a + +enable.available.themes.parameter = Habilitar troca de tema +enable.available.mdx.parameter = Habilitar painel MDX \ No newline at end of file diff --git a/pivot4j-analytics/src/main/resources/org/pivot4j/analytics/primefaces/util/messages/messages_pt_BR.properties b/pivot4j-analytics/src/main/resources/org/pivot4j/analytics/primefaces/util/messages/messages_pt_BR.properties new file mode 100644 index 00000000..d7c43317 --- /dev/null +++ b/pivot4j-analytics/src/main/resources/org/pivot4j/analytics/primefaces/util/messages/messages_pt_BR.properties @@ -0,0 +1,72 @@ +# ============================================================================== +# Component Errors +# ============================================================================== +javax.faces.component.UIInput.CONVERSION={0}: Ocorreu um erro de convers\u00e3o. +javax.faces.component.UIInput.REQUIRED={0}: Erro de valida\u00e7\u00e3o: o valor \u00e9 necess\u00e1rio. +javax.faces.component.UIInput.UPDATE={0}: Ocorreu um erro ao processar as informa\u00e7\u00f5es enviadas. +javax.faces.component.UISelectOne.INVALID={0}: Erro de valida\u00e7\u00e3o: o valor n\u00e3o \u00e9 v\u00e1lido +javax.faces.component.UISelectMany.INVALID={0}: Erro de valida\u00e7\u00e3o: o valor n\u00e3o \u00e9 v\u00e1lido +# ============================================================================== +# Converter Errors +# ============================================================================== +javax.faces.converter.BigDecimalConverter.DECIMAL={2}: ''{0}'' deve ser um n\u00famero decimal com sinal. +javax.faces.converter.BigDecimalConverter.DECIMAL_detail={2}: ''{0}'' deve ser um n\u00famero decimal com sinal formado por zero ou mais d\u00edgitos, que pode ser seguido de um ponto ou fra\u00e7\u00e3o decimal. Exemplo: {1} +javax.faces.converter.BigIntegerConverter.BIGINTEGER={2}: ''{0}'' deve ser um n\u00famero formado por um ou mais d\u00edgitos. +javax.faces.converter.BigIntegerConverter.BIGINTEGER_detail={2}: ''{0}'' deve ser um n\u00famero formado por um ou mais d\u00edgitos. Exemplo: {1} +javax.faces.converter.BooleanConverter.BOOLEAN={1}: ''{0}'' deve ser 'verdadeiro' ou 'falso'. +javax.faces.converter.BooleanConverter.BOOLEAN_detail={1}: ''{0}'' deve ser 'verdadeiro' ou 'falso'. Qualquer valor diferente de 'verdadeiro' se avaliar\u00e1 como 'falso'. +javax.faces.converter.ByteConverter.BYTE={2}: ''{0}'' deve ser um n\u00famero entre 0 e 255. +javax.faces.converter.ByteConverter.BYTE_detail={2}: ''{0}'' deve ser um n\u00famero entre 0 e 255. Exemplo: {1} +javax.faces.converter.CharacterConverter.CHARACTER={1}: ''{0}'' deve ser um caractere v\u00e1lido. +javax.faces.converter.CharacterConverter.CHARACTER_detail={1}: ''{0}'' deve ser um caractere v\u00e1lido ASCII. +javax.faces.converter.DateTimeConverter.DATE={2}: n\u00e3o foi poss\u00edvel reconhecer ''{0}'' como uma data. +javax.faces.converter.DateTimeConverter.DATE_detail={2}: n\u00e3o foi poss\u00edvel reconhecer ''{0}'' como uma data. Exemplo: {1} +javax.faces.converter.DateTimeConverter.TIME={2}: n\u00e3o foi poss\u00edvel reconhecer ''{0}'' como uma hora. +javax.faces.converter.DateTimeConverter.TIME_detail={2}: n\u00e3o foi poss\u00edvel reconhecer ''{0}'' como uma hora. Exemplo: {1} +javax.faces.converter.DateTimeConverter.DATETIME={2}: n\u00e3o foi poss\u00edvel reconhecer ''{0}'' como uma data e hora. +javax.faces.converter.DateTimeConverter.DATETIME_detail={2}: n\u00e3o foi poss\u00edvel reconhecer ''{0}'' como uma data e hora. Exemplo: {1} +javax.faces.converter.DateTimeConverter.PATTERN_TYPE={1}: Um atributo 'pattern' ou 'type' deve ser especificado para converter o valor ''{0}''. +javax.faces.converter.DoubleConverter.DOUBLE={2}: ''{0}'' deve ser um n\u00famero formado por um ou mais d\u00edgitos. +javax.faces.converter.DoubleConverter.DOUBLE_detail={2}: ''{0}'' deve ser um n\u00famero entre 4.9E-324 e 1.7976931348623157E308 Exemplo: {1} +javax.faces.converter.EnumConverter.ENUM={2}: ''{0}'' deve ser convert\u00edvel em um enum. +javax.faces.converter.EnumConverter.ENUM_detail={2}: ''{0}'' deve ser convert\u00edvel em um enum de um enum que contenha a constante ''{1}''. +javax.faces.converter.EnumConverter.ENUM_NO_CLASS={1}: ''{0}'' deve ser convert\u00edvel em um enum do enum, mas sem nenhuma classe enum fornecida. +javax.faces.converter.EnumConverter.ENUM_NO_CLASS_detail={1}: ''{0}'' deve ser convert\u00edvel em um enum do enum, mas sem nenhuma classe enum fornecida. +javax.faces.converter.FloatConverter.FLOAT={2}: ''{0}'' deve ser um n\u00famero formado por um ou mais d\u00edgitos. +javax.faces.converter.FloatConverter.FLOAT_detail={2}: ''{0}'' deve ser um n\u00famero entre 1.4E-45 e 3.4028235E38 Exemplo: {1} +javax.faces.converter.IntegerConverter.INTEGER={2}: ''{0}'' deve ser um n\u00famero formado por um ou mais d\u00edgitos. +javax.faces.converter.IntegerConverter.INTEGER_detail={2}: ''{0}'' deve ser um n\u00famero entre -2147483648 e 2147483647 Exemplo: {1} +javax.faces.converter.LongConverter.LONG={2}: ''{0}'' deve ser um n\u00famero formado por um ou mais d\u00edgitos. +javax.faces.converter.LongConverter.LONG_detail={2}: ''{0}'' deve ser um n\u00famero entre -9223372036854775808 a 9223372036854775807 Exemplo: {1} +javax.faces.converter.NumberConverter.CURRENCY={2}: n\u00e3o foi poss\u00edvel reconhecer ''{0}'' como um valor monet\u00e1rio. +javax.faces.converter.NumberConverter.CURRENCY_detail={2}: n\u00e3o foi poss\u00edvel reconhecer ''{0}'' como um valor monet\u00e1rio. Exemplo: {1} +javax.faces.converter.NumberConverter.PERCENT={2}: n\u00e3o foi poss\u00edvel reconhecer ''{0}'' como uma porcentagem. +javax.faces.converter.NumberConverter.PERCENT_detail={2}: n\u00e3o foi poss\u00edvel reconhecer ''{0}'' como uma porcentagem. Exemplo: {1} +javax.faces.converter.NumberConverter.NUMBER={2}: ''{0}'' n\u00e3o \u00e9 um n\u00famero. +javax.faces.converter.NumberConverter.NUMBER_detail={2}: ''{0}'' n\u00e3o \u00e9 um n\u00famero. Exemplo: {1} +javax.faces.converter.NumberConverter.PATTERN={2}: ''{0}'' n\u00e3o \u00e9 um padr\u00e3o de n\u00famero. +javax.faces.converter.NumberConverter.PATTERN_detail={2}: ''{0}'' n\u00e3o \u00e9 um padr\u00e3o de n\u00famero. Exemplo: {1} +javax.faces.converter.ShortConverter.SHORT={2}: ''{0}'' deve ser um n\u00famero formado por um ou mais d\u00edgitos. +javax.faces.converter.ShortConverter.SHORT_detail={2}: ''{0}'' deve ser um n\u00famero entre -32768 e 32767 Exemplo: {1} +javax.faces.converter.STRING={1}: n\u00e3o foi poss\u00edvel converter ''{0}'' em uma sequ\u00eancia. +# ============================================================================== +# Validator Errors +# ============================================================================== +javax.faces.validator.DoubleRangeValidator.MAXIMUM={1}: Erro de valida\u00e7\u00e3o: o valor \u00e9 maior do que o m\u00e1ximo permitido de "{0}" +javax.faces.validator.DoubleRangeValidator.MINIMUM={1}: Erro de valida\u00e7\u00e3o: o valor \u00e9 menor do que o m\u00ednimo permitido de "{0}" +javax.faces.validator.DoubleRangeValidator.NOT_IN_RANGE={2}: Erro de valida\u00e7\u00e3o: o atributo especificado n\u00e3o est\u00e1 entre os valores esperados de {0} e {1}. +javax.faces.validator.DoubleRangeValidator.TYPE={0}: Erro de valida\u00e7\u00e3o: o valor n\u00e3o \u00e9 do tipo correto +javax.faces.validator.LengthValidator.MAXIMUM={1}: Erro de valida\u00e7\u00e3o: o comprimento \u00e9 maior do que o m\u00e1ximo permitido de "{0}" +javax.faces.validator.LengthValidator.MINIMUM={1}: Erro de valida\u00e7\u00e3o: o comprimento \u00e9 menor do que o m\u00ednimo permitido de "{0}" +javax.faces.validator.LongRangeValidator.MAXIMUM={1}: Erro de valida\u00e7\u00e3o: o valor \u00e9 maior do que o m\u00e1ximo permitido de "{0}" +javax.faces.validator.LongRangeValidator.MINIMUM={1}: Erro de valida\u00e7\u00e3o: o valor \u00e9 menor do que o m\u00ednimo permitido de "{0}" +javax.faces.validator.LongRangeValidator.NOT_IN_RANGE={2}: Erro de valida\u00e7\u00e3o: o atributo especificado n\u00e3o est\u00e1 entre os valores esperados de {0} e {1}. +javax.faces.validator.LongRangeValidator.TYPE={0}: Erro de valida\u00e7\u00e3o: o valor n\u00e3o \u00e9 do tipo correto. +javax.faces.validator.NOT_IN_RANGE=Erro de valida\u00e7\u00e3o: o atributo especificado n\u00e3o est\u00e1 entre os valores esperados de {0} e {1}. +javax.faces.validator.RegexValidator.PATTERN_NOT_SET=O padr\u00e3o Regex deve ser definido. +javax.faces.validator.RegexValidator.PATTERN_NOT_SET_detail=O padr\u00e3o Regex deve ser definido como um valor n\u00e3o vazio. +javax.faces.validator.RegexValidator.NOT_MATCHED=Padr\u00e3o Regex n\u00e3o corresponde +javax.faces.validator.RegexValidator.NOT_MATCHED_detail=O padr\u00e3o Regex de ''{0}'' n\u00e3o corresponde +javax.faces.validator.RegexValidator.MATCH_EXCEPTION=Erro na express\u00e3o regular. +javax.faces.validator.RegexValidator.MATCH_EXCEPTION_detail=Erro na express\u00e3o regular, ''{0}'' +javax.faces.validator.BeanValidator.MESSAGE={0} \ No newline at end of file diff --git a/pivot4j-analytics/src/main/webapp/META-INF/context.xml b/pivot4j-analytics/src/main/webapp/META-INF/context.xml new file mode 100644 index 00000000..4b798257 --- /dev/null +++ b/pivot4j-analytics/src/main/webapp/META-INF/context.xml @@ -0,0 +1,2 @@ + + diff --git a/pivot4j-analytics/src/main/webapp/WEB-INF/FoodMart.xml b/pivot4j-analytics/src/main/webapp/WEB-INF/FoodMart.xml index a3aa6375..10d20eaf 100644 --- a/pivot4j-analytics/src/main/webapp/WEB-INF/FoodMart.xml +++ b/pivot4j-analytics/src/main/webapp/WEB-INF/FoodMart.xml @@ -1,828 +1,828 @@ - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - -
- - - - - - -
- - - - - -
- - - - - - - - - -
-
- - - - - - - - - - - - - -
- - - - - - - - - - - - Verkaufen - Ventes - Cube des ventes - Cube Verkaufen - Cube den Verkaufen - -
- - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - -
- - - - - -
- - - - - - -"fname" || ' ' || "lname" - - -`customer`.`fullname` - - -"fname" || ' ' || "lname" - - -fname + ' ' + lname - - -"fname" || ' ' || "lname" - - -CONCAT(`customer`.`fname`, ' ', `customer`.`lname`) - - -fname + ' ' + lname - - -"customer"."fullname" - - -CONCAT(CONCAT("customer"."fname", ' '), "customer"."lname") - - -"fname" || ' ' || "lname" - - -"customer"."fullname" - - -"fname" || ' ' || "lname" - - -fullname - - - - -"fname" || ' ' || "lname" - - -"fname" || ' ' || "lname" - - -fname + ' ' + lname - - -"fname" || ' ' || "lname" - - -CONCAT(`customer`.`fname`, ' ', `customer`.`lname`) - - -fname + ' ' + lname - - -"customer"."fullname" - - -"customer"."fullname" - - -CONCAT(CONCAT("customer"."fname", ' '), "customer"."lname") - - -"fname" || ' ' || "lname" - - -fullname - - - - - - - - - - - -
- - - - - -
- - - - - -
- - - - - -
- - - - - - - - - - - - -Iif("sales_fact_1997"."promotion_id" = 0, 0, "sales_fact_1997"."store_sales") - - -(case when "sales_fact_1997"."promotion_id" = 0 then 0 else "sales_fact_1997"."store_sales" end) - - -(case when "sales_fact_1997"."promotion_id" = 0 then 0 else "sales_fact_1997"."store_sales" end) - - -(case when "sales_fact_1997"."promotion_id" = 0 then 0 else "sales_fact_1997"."store_sales" end) - - -(case when `sales_fact_1997`.`promotion_id` = 0 then 0 else `sales_fact_1997`.`store_sales` end) - - - -(case when "sales_fact_1997"."promotion_id" = 0 then 0 else "sales_fact_1997"."store_sales" end) - - -`sales_fact_1997`.`store_sales` - - -(case when "sales_fact_1997"."promotion_id" = 0 then 0 else "sales_fact_1997"."store_sales" end) - - -(case when "sales_fact_1997"."promotion_id" = 0 then 0 else "sales_fact_1997"."store_sales" end) - - -(case when "sales_fact_1997"."promotion_id" = 0 then 0 else "sales_fact_1997"."store_sales" end) - - -(case when sales_fact_1997.promotion_id = 0 then 0 else sales_fact_1997.store_sales end) - - - - - [Measures].[Store Sales] - [Measures].[Store Cost] - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - -`warehouse_sales` - `inventory_fact_1997`.`warehouse_cost` - - -`warehouse_sales` - `inventory_fact_1997`.`warehouse_cost` - - + + + + + + +
+ + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + + + + + +
+ + + + + +
+ + + + + + + + + +
+
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + Verkaufen + Ventes + Cube des ventes + Cube Verkaufen + Cube den Verkaufen + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ + + + + +
+ + + + + + + "fname" || ' ' || "lname" + + + `customer`.`fullname` + + + "fname" || ' ' || "lname" + + + fname + ' ' + lname + + + "fname" || ' ' || "lname" + + + CONCAT(`customer`.`fname`, ' ', `customer`.`lname`) + + + fname + ' ' + lname + + + "customer"."fullname" + + + CONCAT(CONCAT("customer"."fname", ' '), "customer"."lname") + + + "fname" || ' ' || "lname" + + + "customer"."fullname" + + + "fname" || ' ' || "lname" + + + fullname + + + + + "fname" || ' ' || "lname" + + + "fname" || ' ' || "lname" + + + fname + ' ' + lname + + + "fname" || ' ' || "lname" + + + CONCAT(`customer`.`fname`, ' ', `customer`.`lname`) + + + fname + ' ' + lname + + + "customer"."fullname" + + + "customer"."fullname" + + + CONCAT(CONCAT("customer"."fname", ' '), "customer"."lname") + + + "fname" || ' ' || "lname" + + + fullname + + + + + + + + + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + + + + + + + + + Iif("sales_fact_1997"."promotion_id" = 0, 0, "sales_fact_1997"."store_sales") + + + (case when "sales_fact_1997"."promotion_id" = 0 then 0 else "sales_fact_1997"."store_sales" end) + + + (case when "sales_fact_1997"."promotion_id" = 0 then 0 else "sales_fact_1997"."store_sales" end) + + + (case when "sales_fact_1997"."promotion_id" = 0 then 0 else "sales_fact_1997"."store_sales" end) + + + (case when `sales_fact_1997`.`promotion_id` = 0 then 0 else `sales_fact_1997`.`store_sales` end) + + + + (case when "sales_fact_1997"."promotion_id" = 0 then 0 else "sales_fact_1997"."store_sales" end) + + + `sales_fact_1997`.`store_sales` + + + (case when "sales_fact_1997"."promotion_id" = 0 then 0 else "sales_fact_1997"."store_sales" end) + + + (case when "sales_fact_1997"."promotion_id" = 0 then 0 else "sales_fact_1997"."store_sales" end) + + + (case when "sales_fact_1997"."promotion_id" = 0 then 0 else "sales_fact_1997"."store_sales" end) + + + (case when sales_fact_1997.promotion_id = 0 then 0 else sales_fact_1997.store_sales end) + + + + + [Measures].[Store Sales] - [Measures].[Store Cost] + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + `warehouse_sales` - `inventory_fact_1997`.`warehouse_cost` + + + `warehouse_sales` - `inventory_fact_1997`.`warehouse_cost` + + "warehouse_sales" - "inventory_fact_1997"."warehouse_cost" - - - - - [Measures].[Warehouse Sales] / [Measures].[Warehouse Cost] - - - - TopCount([Warehouse].[Warehouse Name].MEMBERS, 5, [Measures].[Warehouse Sales]) - - - - - -
- - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - - - - - - -
+ + + + + [Measures].[Warehouse Sales] / [Measures].[Warehouse Cost] + + + + TopCount([Warehouse].[Warehouse Name].MEMBERS, 5, [Measures].[Warehouse Sales]) + + + + +
- - - - - - - - - - - - - - - - - - - - -
-
- - - - - - - - -
-
- - - - - - - -
- - - - - - - -
- - - - - -
- - -
- - - - - - - - - - - - - - - - - - - - -
- - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - -
- - - - - -
- - - - - -
- - - - - - -"fname" || ' ' || "lname" - - -"fname" || ' ' || "lname" - - -fname + ' ' + lname - - -"fname" || ' ' || "lname" - - -CONCAT(`customer`.`fname`, ' ', `customer`.`lname`) - - -fname + ' ' + lname - - -"customer"."fullname" - - -CONCAT(CONCAT("customer"."fname", ' '), "customer"."lname") - - -"fname" || ' ' || "lname" - - -"customer"."fullname" - - -fullname - - - - - - - - - - - -
- - - - - -
- - - - - -
- - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - [Measures].[Store Sales] - [Measures].[Store Cost] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - [Measures].[Profit] / [Measures].[Units Shipped] - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
+ + + + + + + +
+ + + + + + + +
+ + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + +
+ + + + + +
+ + + + + +
+ + + + + + + "fname" || ' ' || "lname" + + + "fname" || ' ' || "lname" + + + fname + ' ' + lname + + + "fname" || ' ' || "lname" + + + CONCAT(`customer`.`fname`, ' ', `customer`.`lname`) + + + fname + ' ' + lname + + + "customer"."fullname" + + + CONCAT(CONCAT("customer"."fname", ' '), "customer"."lname") + + + "fname" || ' ' || "lname" + + + "customer"."fullname" + + + fullname + + + + + + + + + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + [Measures].[Store Sales] - [Measures].[Store Cost] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [Measures].[Profit] / [Measures].[Units Shipped] + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pivot4j-analytics/src/main/webapp/WEB-INF/beans.xml b/pivot4j-analytics/src/main/webapp/WEB-INF/beans.xml new file mode 100644 index 00000000..e69de29b diff --git a/pivot4j-analytics/src/main/webapp/WEB-INF/faces-config.xml b/pivot4j-analytics/src/main/webapp/WEB-INF/faces-config.xml index c440c439..235ce772 100644 --- a/pivot4j-analytics/src/main/webapp/WEB-INF/faces-config.xml +++ b/pivot4j-analytics/src/main/webapp/WEB-INF/faces-config.xml @@ -1,41 +1,51 @@ - - - org.pivot4j.analytics.i18n.messages - msg - - org.pivot4j.analytics.i18n.messages - - en - en - ko - pt - pt_BR - fr - de - es - es_MX - hi - nl - it - ru - - + xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"> + + + pt_BR + en + ko + pt_BR + pt + fr + de + es + es_MX + hi + nl + it + ru + + - - - org.pivot4j.analytics.exception.Pivot4JExceptionHandlerFactory - + + + org.pivot4j.analytics.i18n.messages + msg + + - - org.pivot4j.analytics.listener.LocaleInitializer - + + org.pivot4j.analytics.primefaces.util.messages + + + + org.pivot4j.analytics.i18n.messages + + + + org.pivot4j.analytics.exception.ViewExpiredExceptionHandlerFactory + - - org.primefaces.component.Tree - org.pivot4j.analytics.component.tree.Tree - - + + org.pivot4j.analytics.listener.LocaleInitializer + + + + + org.primefaces.component.Tree + org.pivot4j.analytics.component.tree.Tree + + \ No newline at end of file diff --git a/pivot4j-analytics/src/main/webapp/WEB-INF/glassfish-web.xml b/pivot4j-analytics/src/main/webapp/WEB-INF/glassfish-web.xml index dde9c77e..010552f5 100644 --- a/pivot4j-analytics/src/main/webapp/WEB-INF/glassfish-web.xml +++ b/pivot4j-analytics/src/main/webapp/WEB-INF/glassfish-web.xml @@ -1,7 +1,7 @@ - - /pivot4j - - - \ No newline at end of file + + /pivot4j + + + diff --git a/pivot4j-analytics/src/main/webapp/WEB-INF/pivot4j-config.xml b/pivot4j-analytics/src/main/webapp/WEB-INF/pivot4j-config.xml index 091a744c..46357da0 100644 --- a/pivot4j-analytics/src/main/webapp/WEB-INF/pivot4j-config.xml +++ b/pivot4j-analytics/src/main/webapp/WEB-INF/pivot4j-config.xml @@ -12,8 +12,8 @@ http://www.olap4j.org/ --> - FoodMart Mondrian - FoodMart sample data source. + Pivot4J + Pivot4J data source. jdbc:mondrian: @@ -35,10 +35,11 @@ You can also use '${FS}' to denote the OS specific file separator character. --> + file:${webRoot}${FS}FoodMart.xml jdbc:derby:${webRoot}${FS}foodmart org.apache.derby.jdbc.EmbeddedDriver - sa + @@ -70,62 +71,81 @@ You can download more themes from the below site and install them under the application library directory (i.e. '/WEB-INF/lib') : - http://www.primefaces.org/themes.html - --> - - redmond - - - - - - - - - - - - - eclipse - - - - - - - - - pivot4j - - - - - - - - - - - - - - locale - - - viewId - - - fileId - - - path - - \ No newline at end of file + http://www.primefaces.org/themes.html + --> + + admin + + + + + + + + + + + + + + eclipse + + + + + + + + + pivot4j + + + client + + + + + + no + + + token_validation + + + + + + + + + + + + + + locale + + + viewId + + + fileId + + + path + + pivot4j + + diff --git a/pivot4j-analytics/src/main/webapp/WEB-INF/web.xml b/pivot4j-analytics/src/main/webapp/WEB-INF/web.xml index 3e96e1b6..014272b0 100644 --- a/pivot4j-analytics/src/main/webapp/WEB-INF/web.xml +++ b/pivot4j-analytics/src/main/webapp/WEB-INF/web.xml @@ -1,93 +1,119 @@ - - - Pivot4J Analytics - - - - Project stage for the application (new in 2.0). Expects one of + + + Pivot4J Analytics + + + Project stage for the application (new in 2.0). Expects one of the following values: Development, Production, SystemTest, UnitTest - javax.faces.PROJECT_STAGE - Development - - - + javax.faces.PROJECT_STAGE + Production + + + If this parameter is set to true and the submitted value of a component is the empty string, the submitted value will be set to null - javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL - true - - - Define the state method to be used. There are two different options + javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL + true + + + Define the state method to be used. There are two different options defined by the specification: 'client' and 'server' state. - javax.faces.STATE_SAVING_METHOD - server - - - javax.faces.PARTIAL_STATE_SAVING - false - - - org.apache.myfaces.SERIALIZE_STATE_IN_SESSION - false - - - org.apache.myfaces.LOG_WEB_CONTEXT_PARAMS - false - - - primefaces.THEME - #{workbenchHandler.theme} - - - org.jboss.jbossfaces.WAR_BUNDLES_JSF_IMPL - true - - - - org.apache.logging.log4j.web.Log4jServletContextListener - - - - log4jServletFilter - org.apache.logging.log4j.web.Log4jServletFilter - - - log4jServletFilter - /* - REQUEST - FORWARD - INCLUDE - ERROR - - - - - Faces Servlet - javax.faces.webapp.FacesServlet - 1 - - - - - Faces Servlet - *.xhtml - - - - css - text/css - - - js - text/javascript - - - - - index.xhtml - + javax.faces.STATE_SAVING_METHOD + server + + + javax.faces.PARTIAL_STATE_SAVING + false + + + org.apache.myfaces.SERIALIZE_STATE_IN_SESSION + false + + + org.apache.myfaces.LOG_WEB_CONTEXT_PARAMS + false + + + primefaces.FONT_AWESOME + true + + + primefaces.THEME + #{workbenchHandler.theme} + + + org.jboss.jbossfaces.WAR_BUNDLES_JSF_IMPL + true + + + org.apache.logging.log4j.web.Log4jServletContextListener + + + log4jServletFilter + org.apache.logging.log4j.web.Log4jServletFilter + + + log4jServletFilter + /* + REQUEST + FORWARD + INCLUDE + ERROR + + + + + CorsFilter + org.pivot4j.analytics.util.CORSFilter + + + CorsFilter + /* + + + + Faces Servlet + javax.faces.webapp.FacesServlet + 1 + + + + Faces Servlet + *.xhtml + + + css + text/css + + + js + text/javascript + + + eot + application/vnd.ms-fontobject + + + otf + font/opentype + + + ttf + application/x-font-ttf + + + woff + application/x-font-woff + + + svg + image/svg+xml + + + + index.xhtml + + diff --git a/pivot4j-analytics/src/main/webapp/about.xhtml b/pivot4j-analytics/src/main/webapp/about.xhtml index c9fe7e3c..5f6c022d 100644 --- a/pivot4j-analytics/src/main/webapp/about.xhtml +++ b/pivot4j-analytics/src/main/webapp/about.xhtml @@ -1,28 +1,27 @@ - - - - - - - - - - - - - - + xmlns:h="http://java.sun.com/jsf/html" + xmlns:f="http://java.sun.com/jsf/core" + xmlns:ui="http://java.sun.com/jsf/facelets" + xmlns:p="http://primefaces.org/ui"> + + + + + + + + + + + + + + diff --git a/pivot4j-analytics/src/main/webapp/aggregation.xhtml b/pivot4j-analytics/src/main/webapp/aggregation.xhtml index e85402ea..b748132a 100644 --- a/pivot4j-analytics/src/main/webapp/aggregation.xhtml +++ b/pivot4j-analytics/src/main/webapp/aggregation.xhtml @@ -1,228 +1,227 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pivot4j-analytics/src/main/webapp/catalog.xhtml b/pivot4j-analytics/src/main/webapp/catalog.xhtml index caa53244..3d72719e 100644 --- a/pivot4j-analytics/src/main/webapp/catalog.xhtml +++ b/pivot4j-analytics/src/main/webapp/catalog.xhtml @@ -1,96 +1,95 @@ - - - #{msg['title']} + xmlns:h="http://java.sun.com/jsf/html" + xmlns:f="http://java.sun.com/jsf/core" + xmlns:p="http://primefaces.org/ui" + xmlns:pe="http://primefaces.org/ui/extensions" + xmlns:c="http://java.sun.com/jsp/jstl/core"> + + + #{msg['title']} - + - + - - + + - - + + - - - - - + + + + + - - - - - - - - - - + + + + + + + + + + - - - - - + + + + + - - - - - - + + + + + + - - - + + + - - - - - + + + + + - + - - - - - - + + + + + + - - + + diff --git a/pivot4j-analytics/src/main/webapp/chart.xhtml b/pivot4j-analytics/src/main/webapp/chart.xhtml index 5639176f..ff6ffe88 100644 --- a/pivot4j-analytics/src/main/webapp/chart.xhtml +++ b/pivot4j-analytics/src/main/webapp/chart.xhtml @@ -1,138 +1,137 @@ - - - - - - - - - - + xmlns:h="http://java.sun.com/jsf/html" + xmlns:f="http://java.sun.com/jsf/core" + xmlns:ui="http://java.sun.com/jsf/facelets" + xmlns:p="http://primefaces.org/ui"> + + + + + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - - + + + + + + + - - + + - - - - - - - - + + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - + + + + + + + + + diff --git a/pivot4j-analytics/src/main/webapp/chartexport.xhtml b/pivot4j-analytics/src/main/webapp/chartexport.xhtml new file mode 100644 index 00000000..cd4ca79f --- /dev/null +++ b/pivot4j-analytics/src/main/webapp/chartexport.xhtml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + diff --git a/pivot4j-analytics/src/main/webapp/drillthrough.xhtml b/pivot4j-analytics/src/main/webapp/drillthrough.xhtml index d06477d2..9c549f15 100644 --- a/pivot4j-analytics/src/main/webapp/drillthrough.xhtml +++ b/pivot4j-analytics/src/main/webapp/drillthrough.xhtml @@ -1,107 +1,107 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pivot4j-analytics/src/main/webapp/embed.xhtml b/pivot4j-analytics/src/main/webapp/embed.xhtml index fc5a6a1f..63442142 100644 --- a/pivot4j-analytics/src/main/webapp/embed.xhtml +++ b/pivot4j-analytics/src/main/webapp/embed.xhtml @@ -1,113 +1,116 @@ - - - #{msg['title']} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + xmlns:h="http://java.sun.com/jsf/html" + xmlns:f="http://java.sun.com/jsf/core" + xmlns:ui="http://java.sun.com/jsf/facelets" + xmlns:p="http://primefaces.org/ui" + xmlns:pe="http://primefaces.org/ui/extensions" + xmlns:c="http://java.sun.com/jsp/jstl/core"> + + + + #{msg['title']} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pivot4j-analytics/src/main/webapp/export.xhtml b/pivot4j-analytics/src/main/webapp/export.xhtml index b8247449..d90ba0b1 100644 --- a/pivot4j-analytics/src/main/webapp/export.xhtml +++ b/pivot4j-analytics/src/main/webapp/export.xhtml @@ -1,104 +1,104 @@ - - - - - - - - + xmlns:h="http://java.sun.com/jsf/html" + xmlns:f="http://java.sun.com/jsf/core" + xmlns:ui="http://java.sun.com/jsf/facelets" + xmlns:p="http://primefaces.org/ui" + xmlns:pe="http://primefaces.org/ui/extensions"> + + + + + + + + - - + + - - - - - + + + + + - - - - + + + + - - + + - - - - - + + + + + - - - - - + + + + + - - + + - + - - - - - - + + + + + + - - - - - - + + + + + + - - - + + + - - - - - - + + + + + + diff --git a/pivot4j-analytics/src/main/webapp/extension.xhtml b/pivot4j-analytics/src/main/webapp/extension.xhtml index cccfa43d..bc027d09 100644 --- a/pivot4j-analytics/src/main/webapp/extension.xhtml +++ b/pivot4j-analytics/src/main/webapp/extension.xhtml @@ -1,3 +1,3 @@ + xmlns:ui="http://java.sun.com/jsf/facelets"> \ No newline at end of file diff --git a/pivot4j-analytics/src/main/webapp/hierarchy.xhtml b/pivot4j-analytics/src/main/webapp/hierarchy.xhtml index e2d08f1f..3daf98ee 100644 --- a/pivot4j-analytics/src/main/webapp/hierarchy.xhtml +++ b/pivot4j-analytics/src/main/webapp/hierarchy.xhtml @@ -1,174 +1,173 @@ - - - - - - - - - + xmlns:h="http://java.sun.com/jsf/html" + xmlns:f="http://java.sun.com/jsf/core" + xmlns:ui="http://java.sun.com/jsf/facelets" + xmlns:p="http://primefaces.org/ui"> + + + + + + + + + - - - - + + + + - - - - + + + + - - + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - + + + + + + - - - - + + + + - - - - + + + + - - + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - - + + + + + + + - + - + - - - - - - - - - + + + + + + + + + diff --git a/pivot4j-analytics/src/main/webapp/index.xhtml b/pivot4j-analytics/src/main/webapp/index.xhtml index 7afb4ccd..37da85e5 100644 --- a/pivot4j-analytics/src/main/webapp/index.xhtml +++ b/pivot4j-analytics/src/main/webapp/index.xhtml @@ -1,354 +1,363 @@ - + - - - #{msg['title']} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
    -
    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    + xmlns:h="http://java.sun.com/jsf/html" + xmlns:f="http://java.sun.com/jsf/core" + xmlns:ui="http://java.sun.com/jsf/facelets" + xmlns:p="http://primefaces.org/ui" + xmlns:pe="http://primefaces.org/ui/extensions" + xmlns:c="http://java.sun.com/jsp/jstl/core"> + + + #{msg['title']} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Logout + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      +
      +
      +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      diff --git a/pivot4j-analytics/src/main/webapp/open.xhtml b/pivot4j-analytics/src/main/webapp/open.xhtml index 23a01d53..c20217bd 100644 --- a/pivot4j-analytics/src/main/webapp/open.xhtml +++ b/pivot4j-analytics/src/main/webapp/open.xhtml @@ -1,16 +1,12 @@ - - - - - + xmlns:f="http://java.sun.com/jsf/core"> + + + - - - + + + diff --git a/pivot4j-analytics/src/main/webapp/properties.xhtml b/pivot4j-analytics/src/main/webapp/properties.xhtml index 07af54e0..6a1729df 100644 --- a/pivot4j-analytics/src/main/webapp/properties.xhtml +++ b/pivot4j-analytics/src/main/webapp/properties.xhtml @@ -1,108 +1,108 @@ - - - - - - + xmlns:h="http://java.sun.com/jsf/html" + xmlns:f="http://java.sun.com/jsf/core" + xmlns:ui="http://java.sun.com/jsf/facelets" + xmlns:p="http://primefaces.org/ui" + xmlns:pe="http://primefaces.org/ui/extensions"> + + + + + + - - - - - - - + + + + + + + - - - - - + + + + + - - + + - - - - - - + + + + + + - - -
        -
      • -
      • - - -
      • -
      -
      -
      -
      -
      -
      -
      - - - + + +
        +
      • +
      • + + +
      • +
      +
      +
      + +
      + +
      + + + - - - - - - -
      -
      + + + + + + + +
      diff --git a/pivot4j-analytics/src/main/webapp/resources/pivot4j/css/bootstrap.min.css b/pivot4j-analytics/src/main/webapp/resources/pivot4j/css/bootstrap.min.css new file mode 100644 index 00000000..db7eacfe --- /dev/null +++ b/pivot4j-analytics/src/main/webapp/resources/pivot4j/css/bootstrap.min.css @@ -0,0 +1,7 @@ +/*! + * Bootstrap v4.0.0 (https://getbootstrap.com) + * Copyright 2011-2018 The Bootstrap Authors + * Copyright 2011-2018 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */:root{--blue:#007bff;--indigo:#6610f2;--purple:#6f42c1;--pink:#e83e8c;--red:#dc3545;--orange:#fd7e14;--yellow:#ffc107;--green:#28a745;--teal:#20c997;--cyan:#17a2b8;--white:#fff;--gray:#6c757d;--gray-dark:#343a40;--primary:#007bff;--secondary:#6c757d;--success:#28a745;--info:#17a2b8;--warning:#ffc107;--danger:#dc3545;--light:#f8f9fa;--dark:#343a40;--breakpoint-xs:0;--breakpoint-sm:576px;--breakpoint-md:768px;--breakpoint-lg:992px;--breakpoint-xl:1200px;--font-family-sans-serif:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}@-ms-viewport{width:device-width}article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg:not(:root){overflow:hidden}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-bottom:.5rem;font-family:inherit;font-weight:500;line-height:1.2;color:inherit}.h1,h1{font-size:2.5rem}.h2,h2{font-size:2rem}.h3,h3{font-size:1.75rem}.h4,h4{font-size:1.5rem}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:6rem;font-weight:300;line-height:1.2}.display-2{font-size:5.5rem;font-weight:300;line-height:1.2}.display-3{font-size:4.5rem;font-weight:300;line-height:1.2}.display-4{font-size:3.5rem;font-weight:300;line-height:1.2}hr{margin-top:1rem;margin-bottom:1rem;border:0;border-top:1px solid rgba(0,0,0,.1)}.small,small{font-size:80%;font-weight:400}.mark,mark{padding:.2em;background-color:#fcf8e3}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:90%;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote-footer{display:block;font-size:80%;color:#6c757d}.blockquote-footer::before{content:"\2014 \00A0"}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:.25rem;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:90%;color:#6c757d}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}code{font-size:87.5%;color:#e83e8c;word-break:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:87.5%;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:100%;font-weight:700}pre{display:block;font-size:87.5%;color:#212529}pre code{font-size:inherit;color:inherit;word-break:normal}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:576px){.container{max-width:540px}}@media (min-width:768px){.container{max-width:720px}}@media (min-width:992px){.container{max-width:960px}}@media (min-width:1200px){.container{max-width:1140px}}.container-fluid{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-15px;margin-left:-15px}.no-gutters{margin-right:0;margin-left:0}.no-gutters>.col,.no-gutters>[class*=col-]{padding-right:0;padding-left:0}.col,.col-1,.col-10,.col-11,.col-12,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-auto,.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-auto,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-auto,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-auto,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-auto{position:relative;width:100%;min-height:1px;padding-right:15px;padding-left:15px}.col{-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-auto{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-1{-webkit-box-flex:0;-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-2{-webkit-box-flex:0;-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-3{-webkit-box-flex:0;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-4{-webkit-box-flex:0;-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-5{-webkit-box-flex:0;-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-6{-webkit-box-flex:0;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-7{-webkit-box-flex:0;-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-8{-webkit-box-flex:0;-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-9{-webkit-box-flex:0;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-10{-webkit-box-flex:0;-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-11{-webkit-box-flex:0;-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-12{-webkit-box-flex:0;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-first{-webkit-box-ordinal-group:0;-ms-flex-order:-1;order:-1}.order-last{-webkit-box-ordinal-group:14;-ms-flex-order:13;order:13}.order-0{-webkit-box-ordinal-group:1;-ms-flex-order:0;order:0}.order-1{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.order-2{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.order-3{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.order-4{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.order-5{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.order-6{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.order-7{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.order-8{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.order-9{-webkit-box-ordinal-group:10;-ms-flex-order:9;order:9}.order-10{-webkit-box-ordinal-group:11;-ms-flex-order:10;order:10}.order-11{-webkit-box-ordinal-group:12;-ms-flex-order:11;order:11}.order-12{-webkit-box-ordinal-group:13;-ms-flex-order:12;order:12}.offset-1{margin-left:8.333333%}.offset-2{margin-left:16.666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.333333%}.offset-5{margin-left:41.666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.333333%}.offset-8{margin-left:66.666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.333333%}.offset-11{margin-left:91.666667%}@media (min-width:576px){.col-sm{-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-sm-auto{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-sm-1{-webkit-box-flex:0;-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-sm-2{-webkit-box-flex:0;-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-sm-3{-webkit-box-flex:0;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-sm-4{-webkit-box-flex:0;-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-sm-5{-webkit-box-flex:0;-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-sm-6{-webkit-box-flex:0;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-sm-7{-webkit-box-flex:0;-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-sm-8{-webkit-box-flex:0;-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-sm-9{-webkit-box-flex:0;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-sm-10{-webkit-box-flex:0;-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-sm-11{-webkit-box-flex:0;-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-sm-12{-webkit-box-flex:0;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-sm-first{-webkit-box-ordinal-group:0;-ms-flex-order:-1;order:-1}.order-sm-last{-webkit-box-ordinal-group:14;-ms-flex-order:13;order:13}.order-sm-0{-webkit-box-ordinal-group:1;-ms-flex-order:0;order:0}.order-sm-1{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.order-sm-2{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.order-sm-3{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.order-sm-4{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.order-sm-5{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.order-sm-6{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.order-sm-7{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.order-sm-8{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.order-sm-9{-webkit-box-ordinal-group:10;-ms-flex-order:9;order:9}.order-sm-10{-webkit-box-ordinal-group:11;-ms-flex-order:10;order:10}.order-sm-11{-webkit-box-ordinal-group:12;-ms-flex-order:11;order:11}.order-sm-12{-webkit-box-ordinal-group:13;-ms-flex-order:12;order:12}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.333333%}.offset-sm-2{margin-left:16.666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.333333%}.offset-sm-5{margin-left:41.666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.333333%}.offset-sm-8{margin-left:66.666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.333333%}.offset-sm-11{margin-left:91.666667%}}@media (min-width:768px){.col-md{-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-md-auto{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-md-1{-webkit-box-flex:0;-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-md-2{-webkit-box-flex:0;-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-md-3{-webkit-box-flex:0;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-md-4{-webkit-box-flex:0;-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-md-5{-webkit-box-flex:0;-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-md-6{-webkit-box-flex:0;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-md-7{-webkit-box-flex:0;-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-md-8{-webkit-box-flex:0;-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-md-9{-webkit-box-flex:0;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-md-10{-webkit-box-flex:0;-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-md-11{-webkit-box-flex:0;-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-md-12{-webkit-box-flex:0;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-md-first{-webkit-box-ordinal-group:0;-ms-flex-order:-1;order:-1}.order-md-last{-webkit-box-ordinal-group:14;-ms-flex-order:13;order:13}.order-md-0{-webkit-box-ordinal-group:1;-ms-flex-order:0;order:0}.order-md-1{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.order-md-2{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.order-md-3{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.order-md-4{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.order-md-5{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.order-md-6{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.order-md-7{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.order-md-8{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.order-md-9{-webkit-box-ordinal-group:10;-ms-flex-order:9;order:9}.order-md-10{-webkit-box-ordinal-group:11;-ms-flex-order:10;order:10}.order-md-11{-webkit-box-ordinal-group:12;-ms-flex-order:11;order:11}.order-md-12{-webkit-box-ordinal-group:13;-ms-flex-order:12;order:12}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.333333%}.offset-md-2{margin-left:16.666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.333333%}.offset-md-5{margin-left:41.666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.333333%}.offset-md-8{margin-left:66.666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.333333%}.offset-md-11{margin-left:91.666667%}}@media (min-width:992px){.col-lg{-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-lg-auto{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-lg-1{-webkit-box-flex:0;-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-lg-2{-webkit-box-flex:0;-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-lg-3{-webkit-box-flex:0;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-lg-4{-webkit-box-flex:0;-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-lg-5{-webkit-box-flex:0;-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-lg-6{-webkit-box-flex:0;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-lg-7{-webkit-box-flex:0;-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-lg-8{-webkit-box-flex:0;-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-lg-9{-webkit-box-flex:0;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-lg-10{-webkit-box-flex:0;-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-lg-11{-webkit-box-flex:0;-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-lg-12{-webkit-box-flex:0;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-lg-first{-webkit-box-ordinal-group:0;-ms-flex-order:-1;order:-1}.order-lg-last{-webkit-box-ordinal-group:14;-ms-flex-order:13;order:13}.order-lg-0{-webkit-box-ordinal-group:1;-ms-flex-order:0;order:0}.order-lg-1{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.order-lg-2{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.order-lg-3{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.order-lg-4{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.order-lg-5{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.order-lg-6{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.order-lg-7{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.order-lg-8{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.order-lg-9{-webkit-box-ordinal-group:10;-ms-flex-order:9;order:9}.order-lg-10{-webkit-box-ordinal-group:11;-ms-flex-order:10;order:10}.order-lg-11{-webkit-box-ordinal-group:12;-ms-flex-order:11;order:11}.order-lg-12{-webkit-box-ordinal-group:13;-ms-flex-order:12;order:12}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.333333%}.offset-lg-2{margin-left:16.666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.333333%}.offset-lg-5{margin-left:41.666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.333333%}.offset-lg-8{margin-left:66.666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.333333%}.offset-lg-11{margin-left:91.666667%}}@media (min-width:1200px){.col-xl{-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-xl-auto{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-xl-1{-webkit-box-flex:0;-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-xl-2{-webkit-box-flex:0;-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-xl-3{-webkit-box-flex:0;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-xl-4{-webkit-box-flex:0;-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-xl-5{-webkit-box-flex:0;-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-xl-6{-webkit-box-flex:0;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-xl-7{-webkit-box-flex:0;-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-xl-8{-webkit-box-flex:0;-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-xl-9{-webkit-box-flex:0;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-xl-10{-webkit-box-flex:0;-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-xl-11{-webkit-box-flex:0;-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-xl-12{-webkit-box-flex:0;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-xl-first{-webkit-box-ordinal-group:0;-ms-flex-order:-1;order:-1}.order-xl-last{-webkit-box-ordinal-group:14;-ms-flex-order:13;order:13}.order-xl-0{-webkit-box-ordinal-group:1;-ms-flex-order:0;order:0}.order-xl-1{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.order-xl-2{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.order-xl-3{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.order-xl-4{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.order-xl-5{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.order-xl-6{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.order-xl-7{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.order-xl-8{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.order-xl-9{-webkit-box-ordinal-group:10;-ms-flex-order:9;order:9}.order-xl-10{-webkit-box-ordinal-group:11;-ms-flex-order:10;order:10}.order-xl-11{-webkit-box-ordinal-group:12;-ms-flex-order:11;order:11}.order-xl-12{-webkit-box-ordinal-group:13;-ms-flex-order:12;order:12}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.333333%}.offset-xl-2{margin-left:16.666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.333333%}.offset-xl-5{margin-left:41.666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.333333%}.offset-xl-8{margin-left:66.666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.333333%}.offset-xl-11{margin-left:91.666667%}}.table{width:100%;max-width:100%;margin-bottom:1rem;background-color:transparent}.table td,.table th{padding:.75rem;vertical-align:top;border-top:1px solid #dee2e6}.table thead th{vertical-align:bottom;border-bottom:2px solid #dee2e6}.table tbody+tbody{border-top:2px solid #dee2e6}.table .table{background-color:#fff}.table-sm td,.table-sm th{padding:.3rem}.table-bordered{border:1px solid #dee2e6}.table-bordered td,.table-bordered th{border:1px solid #dee2e6}.table-bordered thead td,.table-bordered thead th{border-bottom-width:2px}.table-striped tbody tr:nth-of-type(odd){background-color:rgba(0,0,0,.05)}.table-hover tbody tr:hover{background-color:rgba(0,0,0,.075)}.table-primary,.table-primary>td,.table-primary>th{background-color:#b8daff}.table-hover .table-primary:hover{background-color:#9fcdff}.table-hover .table-primary:hover>td,.table-hover .table-primary:hover>th{background-color:#9fcdff}.table-secondary,.table-secondary>td,.table-secondary>th{background-color:#d6d8db}.table-hover .table-secondary:hover{background-color:#c8cbcf}.table-hover .table-secondary:hover>td,.table-hover .table-secondary:hover>th{background-color:#c8cbcf}.table-success,.table-success>td,.table-success>th{background-color:#c3e6cb}.table-hover .table-success:hover{background-color:#b1dfbb}.table-hover .table-success:hover>td,.table-hover .table-success:hover>th{background-color:#b1dfbb}.table-info,.table-info>td,.table-info>th{background-color:#bee5eb}.table-hover .table-info:hover{background-color:#abdde5}.table-hover .table-info:hover>td,.table-hover .table-info:hover>th{background-color:#abdde5}.table-warning,.table-warning>td,.table-warning>th{background-color:#ffeeba}.table-hover .table-warning:hover{background-color:#ffe8a1}.table-hover .table-warning:hover>td,.table-hover .table-warning:hover>th{background-color:#ffe8a1}.table-danger,.table-danger>td,.table-danger>th{background-color:#f5c6cb}.table-hover .table-danger:hover{background-color:#f1b0b7}.table-hover .table-danger:hover>td,.table-hover .table-danger:hover>th{background-color:#f1b0b7}.table-light,.table-light>td,.table-light>th{background-color:#fdfdfe}.table-hover .table-light:hover{background-color:#ececf6}.table-hover .table-light:hover>td,.table-hover .table-light:hover>th{background-color:#ececf6}.table-dark,.table-dark>td,.table-dark>th{background-color:#c6c8ca}.table-hover .table-dark:hover{background-color:#b9bbbe}.table-hover .table-dark:hover>td,.table-hover .table-dark:hover>th{background-color:#b9bbbe}.table-active,.table-active>td,.table-active>th{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover>td,.table-hover .table-active:hover>th{background-color:rgba(0,0,0,.075)}.table .thead-dark th{color:#fff;background-color:#212529;border-color:#32383e}.table .thead-light th{color:#495057;background-color:#e9ecef;border-color:#dee2e6}.table-dark{color:#fff;background-color:#212529}.table-dark td,.table-dark th,.table-dark thead th{border-color:#32383e}.table-dark.table-bordered{border:0}.table-dark.table-striped tbody tr:nth-of-type(odd){background-color:rgba(255,255,255,.05)}.table-dark.table-hover tbody tr:hover{background-color:rgba(255,255,255,.075)}@media (max-width:575.98px){.table-responsive-sm{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-sm>.table-bordered{border:0}}@media (max-width:767.98px){.table-responsive-md{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-md>.table-bordered{border:0}}@media (max-width:991.98px){.table-responsive-lg{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-lg>.table-bordered{border:0}}@media (max-width:1199.98px){.table-responsive-xl{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-xl>.table-bordered{border:0}}.table-responsive{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive>.table-bordered{border:0}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;line-height:1.5;color:#495057;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}.form-control::-ms-expand{background-color:transparent;border:0}.form-control:focus{color:#495057;background-color:#fff;border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.form-control::-webkit-input-placeholder{color:#6c757d;opacity:1}.form-control::-moz-placeholder{color:#6c757d;opacity:1}.form-control:-ms-input-placeholder{color:#6c757d;opacity:1}.form-control::-ms-input-placeholder{color:#6c757d;opacity:1}.form-control::placeholder{color:#6c757d;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}select.form-control:not([size]):not([multiple]){height:calc(2.25rem + 2px)}select.form-control:focus::-ms-value{color:#495057;background-color:#fff}.form-control-file,.form-control-range{display:block;width:100%}.col-form-label{padding-top:calc(.375rem + 1px);padding-bottom:calc(.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + 1px);padding-bottom:calc(.5rem + 1px);font-size:1.25rem;line-height:1.5}.col-form-label-sm{padding-top:calc(.25rem + 1px);padding-bottom:calc(.25rem + 1px);font-size:.875rem;line-height:1.5}.form-control-plaintext{display:block;width:100%;padding-top:.375rem;padding-bottom:.375rem;margin-bottom:0;line-height:1.5;background-color:transparent;border:solid transparent;border-width:1px 0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm,.input-group-lg>.form-control-plaintext.form-control,.input-group-lg>.input-group-append>.form-control-plaintext.btn,.input-group-lg>.input-group-append>.form-control-plaintext.input-group-text,.input-group-lg>.input-group-prepend>.form-control-plaintext.btn,.input-group-lg>.input-group-prepend>.form-control-plaintext.input-group-text,.input-group-sm>.form-control-plaintext.form-control,.input-group-sm>.input-group-append>.form-control-plaintext.btn,.input-group-sm>.input-group-append>.form-control-plaintext.input-group-text,.input-group-sm>.input-group-prepend>.form-control-plaintext.btn,.input-group-sm>.input-group-prepend>.form-control-plaintext.input-group-text{padding-right:0;padding-left:0}.form-control-sm,.input-group-sm>.form-control,.input-group-sm>.input-group-append>.btn,.input-group-sm>.input-group-append>.input-group-text,.input-group-sm>.input-group-prepend>.btn,.input-group-sm>.input-group-prepend>.input-group-text{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.input-group-sm>.input-group-append>select.btn:not([size]):not([multiple]),.input-group-sm>.input-group-append>select.input-group-text:not([size]):not([multiple]),.input-group-sm>.input-group-prepend>select.btn:not([size]):not([multiple]),.input-group-sm>.input-group-prepend>select.input-group-text:not([size]):not([multiple]),.input-group-sm>select.form-control:not([size]):not([multiple]),select.form-control-sm:not([size]):not([multiple]){height:calc(1.8125rem + 2px)}.form-control-lg,.input-group-lg>.form-control,.input-group-lg>.input-group-append>.btn,.input-group-lg>.input-group-append>.input-group-text,.input-group-lg>.input-group-prepend>.btn,.input-group-lg>.input-group-prepend>.input-group-text{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.input-group-lg>.input-group-append>select.btn:not([size]):not([multiple]),.input-group-lg>.input-group-append>select.input-group-text:not([size]):not([multiple]),.input-group-lg>.input-group-prepend>select.btn:not([size]):not([multiple]),.input-group-lg>.input-group-prepend>select.input-group-text:not([size]):not([multiple]),.input-group-lg>select.form-control:not([size]):not([multiple]),select.form-control-lg:not([size]):not([multiple]){height:calc(2.875rem + 2px)}.form-group{margin-bottom:1rem}.form-text{display:block;margin-top:.25rem}.form-row{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-5px;margin-left:-5px}.form-row>.col,.form-row>[class*=col-]{padding-right:5px;padding-left:5px}.form-check{position:relative;display:block;padding-left:1.25rem}.form-check-input{position:absolute;margin-top:.3rem;margin-left:-1.25rem}.form-check-input:disabled~.form-check-label{color:#6c757d}.form-check-label{margin-bottom:0}.form-check-inline{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding-left:0;margin-right:.75rem}.form-check-inline .form-check-input{position:static;margin-top:0;margin-right:.3125rem;margin-left:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#28a745}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.5rem;margin-top:.1rem;font-size:.875rem;line-height:1;color:#fff;background-color:rgba(40,167,69,.8);border-radius:.2rem}.custom-select.is-valid,.form-control.is-valid,.was-validated .custom-select:valid,.was-validated .form-control:valid{border-color:#28a745}.custom-select.is-valid:focus,.form-control.is-valid:focus,.was-validated .custom-select:valid:focus,.was-validated .form-control:valid:focus{border-color:#28a745;box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.custom-select.is-valid~.valid-feedback,.custom-select.is-valid~.valid-tooltip,.form-control.is-valid~.valid-feedback,.form-control.is-valid~.valid-tooltip,.was-validated .custom-select:valid~.valid-feedback,.was-validated .custom-select:valid~.valid-tooltip,.was-validated .form-control:valid~.valid-feedback,.was-validated .form-control:valid~.valid-tooltip{display:block}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:#28a745}.form-check-input.is-valid~.valid-feedback,.form-check-input.is-valid~.valid-tooltip,.was-validated .form-check-input:valid~.valid-feedback,.was-validated .form-check-input:valid~.valid-tooltip{display:block}.custom-control-input.is-valid~.custom-control-label,.was-validated .custom-control-input:valid~.custom-control-label{color:#28a745}.custom-control-input.is-valid~ .custom-control-label::before ,.was-validated .custom-control-input:valid~ .custom-control-label::before{background-color:#71dd8a}.custom-control-input.is-valid~.valid-feedback,.custom-control-input.is-valid~.valid-tooltip,.was-validated .custom-control-input:valid~.valid-feedback,.was-validated .custom-control-input:valid~.valid-tooltip{display:block}.custom-control-input.is-valid:checked~ .custom-control-label::before,.was-validated .custom-control-input:valid:checked~ .custom-control-label::before{background-color:#34ce57}.custom-control-input.is-valid:focus~ .custom-control-label::before,.was-validated .custom-control-input:valid:focus~ .custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(40,167,69,.25)}.custom-file-input.is-valid~.custom-file-label,.was-validated .custom-file-input:valid~.custom-file-label{border-color:#28a745}.custom-file-input.is-valid~.custom-file-label::before,.was-validated .custom-file-input:valid~.custom-file-label::before{border-color:inherit}.custom-file-input.is-valid~.valid-feedback,.custom-file-input.is-valid~.valid-tooltip,.was-validated .custom-file-input:valid~.valid-feedback,.was-validated .custom-file-input:valid~.valid-tooltip{display:block}.custom-file-input.is-valid:focus~.custom-file-label,.was-validated .custom-file-input:valid:focus~.custom-file-label{box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#dc3545}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.5rem;margin-top:.1rem;font-size:.875rem;line-height:1;color:#fff;background-color:rgba(220,53,69,.8);border-radius:.2rem}.custom-select.is-invalid,.form-control.is-invalid,.was-validated .custom-select:invalid,.was-validated .form-control:invalid{border-color:#dc3545}.custom-select.is-invalid:focus,.form-control.is-invalid:focus,.was-validated .custom-select:invalid:focus,.was-validated .form-control:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.custom-select.is-invalid~.invalid-feedback,.custom-select.is-invalid~.invalid-tooltip,.form-control.is-invalid~.invalid-feedback,.form-control.is-invalid~.invalid-tooltip,.was-validated .custom-select:invalid~.invalid-feedback,.was-validated .custom-select:invalid~.invalid-tooltip,.was-validated .form-control:invalid~.invalid-feedback,.was-validated .form-control:invalid~.invalid-tooltip{display:block}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:#dc3545}.form-check-input.is-invalid~.invalid-feedback,.form-check-input.is-invalid~.invalid-tooltip,.was-validated .form-check-input:invalid~.invalid-feedback,.was-validated .form-check-input:invalid~.invalid-tooltip{display:block}.custom-control-input.is-invalid~.custom-control-label,.was-validated .custom-control-input:invalid~.custom-control-label{color:#dc3545}.custom-control-input.is-invalid~ .custom-control-label::before,.was-validated .custom-control-input:invalid~ .custom-control-label::before{background-color:#efa2a9}.custom-control-input.is-invalid~.invalid-feedback,.custom-control-input.is-invalid~.invalid-tooltip,.was-validated .custom-control-input:invalid~.invalid-feedback,.was-validated .custom-control-input:invalid~.invalid-tooltip{display:block}.custom-control-input.is-invalid:checked~ .custom-control-label::before,.was-validated .custom-control-input:invalid:checked~ .custom-control-label::before{background-color:#e4606d}.custom-control-input.is-invalid:focus~ .custom-control-label::before,.was-validated .custom-control-input:invalid:focus~ .custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(220,53,69,.25)}.custom-file-input.is-invalid~.custom-file-label,.was-validated .custom-file-input:invalid~.custom-file-label{border-color:#dc3545}.custom-file-input.is-invalid~.custom-file-label::before,.was-validated .custom-file-input:invalid~.custom-file-label::before{border-color:inherit}.custom-file-input.is-invalid~.invalid-feedback,.custom-file-input.is-invalid~.invalid-tooltip,.was-validated .custom-file-input:invalid~.invalid-feedback,.was-validated .custom-file-input:invalid~.invalid-tooltip{display:block}.custom-file-input.is-invalid:focus~.custom-file-label,.was-validated .custom-file-input:invalid:focus~.custom-file-label{box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.form-inline{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row wrap;flex-flow:row wrap;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.form-inline .form-check{width:100%}@media (min-width:576px){.form-inline label{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;margin-bottom:0}.form-inline .form-group{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row wrap;flex-flow:row wrap;-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin-bottom:0}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-plaintext{display:inline-block}.form-inline .input-group{width:auto}.form-inline .form-check{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;width:auto;padding-left:0}.form-inline .form-check-input{position:relative;margin-top:0;margin-right:.25rem;margin-left:0}.form-inline .custom-control{-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.form-inline .custom-control-label{margin-bottom:0}}.btn{display:inline-block;font-weight:400;text-align:center;white-space:nowrap;vertical-align:middle;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border:1px solid transparent;padding:.375rem .75rem;font-size:1rem;line-height:1.5;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}.btn:focus,.btn:hover{text-decoration:none}.btn.focus,.btn:focus{outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.btn.disabled,.btn:disabled{opacity:.65}.btn:not(:disabled):not(.disabled){cursor:pointer}.btn:not(:disabled):not(.disabled).active,.btn:not(:disabled):not(.disabled):active{background-image:none}a.btn.disabled,fieldset:disabled a.btn{pointer-events:none}.btn-primary{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:hover{color:#fff;background-color:#0069d9;border-color:#0062cc}.btn-primary.focus,.btn-primary:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-primary.disabled,.btn-primary:disabled{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:not(:disabled):not(.disabled).active,.btn-primary:not(:disabled):not(.disabled):active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#0062cc;border-color:#005cbf}.btn-primary:not(:disabled):not(.disabled).active:focus,.btn-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-secondary{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:hover{color:#fff;background-color:#5a6268;border-color:#545b62}.btn-secondary.focus,.btn-secondary:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-secondary.disabled,.btn-secondary:disabled{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:not(:disabled):not(.disabled).active,.btn-secondary:not(:disabled):not(.disabled):active,.show>.btn-secondary.dropdown-toggle{color:#fff;background-color:#545b62;border-color:#4e555b}.btn-secondary:not(:disabled):not(.disabled).active:focus,.btn-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-success{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:hover{color:#fff;background-color:#218838;border-color:#1e7e34}.btn-success.focus,.btn-success:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-success.disabled,.btn-success:disabled{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:not(:disabled):not(.disabled).active,.btn-success:not(:disabled):not(.disabled):active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#1e7e34;border-color:#1c7430}.btn-success:not(:disabled):not(.disabled).active:focus,.btn-success:not(:disabled):not(.disabled):active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-info{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:hover{color:#fff;background-color:#138496;border-color:#117a8b}.btn-info.focus,.btn-info:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-info.disabled,.btn-info:disabled{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:not(:disabled):not(.disabled).active,.btn-info:not(:disabled):not(.disabled):active,.show>.btn-info.dropdown-toggle{color:#fff;background-color:#117a8b;border-color:#10707f}.btn-info:not(:disabled):not(.disabled).active:focus,.btn-info:not(:disabled):not(.disabled):active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-warning{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:hover{color:#212529;background-color:#e0a800;border-color:#d39e00}.btn-warning.focus,.btn-warning:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-warning.disabled,.btn-warning:disabled{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:not(:disabled):not(.disabled).active,.btn-warning:not(:disabled):not(.disabled):active,.show>.btn-warning.dropdown-toggle{color:#212529;background-color:#d39e00;border-color:#c69500}.btn-warning:not(:disabled):not(.disabled).active:focus,.btn-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-danger{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:hover{color:#fff;background-color:#c82333;border-color:#bd2130}.btn-danger.focus,.btn-danger:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-danger.disabled,.btn-danger:disabled{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:not(:disabled):not(.disabled).active,.btn-danger:not(:disabled):not(.disabled):active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#bd2130;border-color:#b21f2d}.btn-danger:not(:disabled):not(.disabled).active:focus,.btn-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-light{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{color:#212529;background-color:#e2e6ea;border-color:#dae0e5}.btn-light.focus,.btn-light:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-light.disabled,.btn-light:disabled{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:not(:disabled):not(.disabled).active,.btn-light:not(:disabled):not(.disabled):active,.show>.btn-light.dropdown-toggle{color:#212529;background-color:#dae0e5;border-color:#d3d9df}.btn-light:not(:disabled):not(.disabled).active:focus,.btn-light:not(:disabled):not(.disabled):active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-dark{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:hover{color:#fff;background-color:#23272b;border-color:#1d2124}.btn-dark.focus,.btn-dark:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-dark.disabled,.btn-dark:disabled{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:not(:disabled):not(.disabled).active,.btn-dark:not(:disabled):not(.disabled):active,.show>.btn-dark.dropdown-toggle{color:#fff;background-color:#1d2124;border-color:#171a1d}.btn-dark:not(:disabled):not(.disabled).active:focus,.btn-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-outline-primary{color:#007bff;background-color:transparent;background-image:none;border-color:#007bff}.btn-outline-primary:hover{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary.focus,.btn-outline-primary:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#007bff;background-color:transparent}.btn-outline-primary:not(:disabled):not(.disabled).active,.btn-outline-primary:not(:disabled):not(.disabled):active,.show>.btn-outline-primary.dropdown-toggle{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary:not(:disabled):not(.disabled).active:focus,.btn-outline-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-outline-secondary{color:#6c757d;background-color:transparent;background-image:none;border-color:#6c757d}.btn-outline-secondary:hover{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-outline-secondary.focus,.btn-outline-secondary:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#6c757d;background-color:transparent}.btn-outline-secondary:not(:disabled):not(.disabled).active,.btn-outline-secondary:not(:disabled):not(.disabled):active,.show>.btn-outline-secondary.dropdown-toggle{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-outline-secondary:not(:disabled):not(.disabled).active:focus,.btn-outline-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-outline-success{color:#28a745;background-color:transparent;background-image:none;border-color:#28a745}.btn-outline-success:hover{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success.focus,.btn-outline-success:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#28a745;background-color:transparent}.btn-outline-success:not(:disabled):not(.disabled).active,.btn-outline-success:not(:disabled):not(.disabled):active,.show>.btn-outline-success.dropdown-toggle{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success:not(:disabled):not(.disabled).active:focus,.btn-outline-success:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-outline-info{color:#17a2b8;background-color:transparent;background-image:none;border-color:#17a2b8}.btn-outline-info:hover{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info.focus,.btn-outline-info:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#17a2b8;background-color:transparent}.btn-outline-info:not(:disabled):not(.disabled).active,.btn-outline-info:not(:disabled):not(.disabled):active,.show>.btn-outline-info.dropdown-toggle{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info:not(:disabled):not(.disabled).active:focus,.btn-outline-info:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-outline-warning{color:#ffc107;background-color:transparent;background-image:none;border-color:#ffc107}.btn-outline-warning:hover{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning.focus,.btn-outline-warning:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{color:#ffc107;background-color:transparent}.btn-outline-warning:not(:disabled):not(.disabled).active,.btn-outline-warning:not(:disabled):not(.disabled):active,.show>.btn-outline-warning.dropdown-toggle{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning:not(:disabled):not(.disabled).active:focus,.btn-outline-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-outline-danger{color:#dc3545;background-color:transparent;background-image:none;border-color:#dc3545}.btn-outline-danger:hover{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger.focus,.btn-outline-danger:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#dc3545;background-color:transparent}.btn-outline-danger:not(:disabled):not(.disabled).active,.btn-outline-danger:not(:disabled):not(.disabled):active,.show>.btn-outline-danger.dropdown-toggle{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger:not(:disabled):not(.disabled).active:focus,.btn-outline-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-outline-light{color:#f8f9fa;background-color:transparent;background-image:none;border-color:#f8f9fa}.btn-outline-light:hover{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light.focus,.btn-outline-light:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{color:#f8f9fa;background-color:transparent}.btn-outline-light:not(:disabled):not(.disabled).active,.btn-outline-light:not(:disabled):not(.disabled):active,.show>.btn-outline-light.dropdown-toggle{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:not(:disabled):not(.disabled).active:focus,.btn-outline-light:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-outline-dark{color:#343a40;background-color:transparent;background-image:none;border-color:#343a40}.btn-outline-dark:hover{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark.focus,.btn-outline-dark:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{color:#343a40;background-color:transparent}.btn-outline-dark:not(:disabled):not(.disabled).active,.btn-outline-dark:not(:disabled):not(.disabled):active,.show>.btn-outline-dark.dropdown-toggle{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark:not(:disabled):not(.disabled).active:focus,.btn-outline-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-link{font-weight:400;color:#007bff;background-color:transparent}.btn-link:hover{color:#0056b3;text-decoration:underline;background-color:transparent;border-color:transparent}.btn-link.focus,.btn-link:focus{text-decoration:underline;border-color:transparent;box-shadow:none}.btn-link.disabled,.btn-link:disabled{color:#6c757d}.btn-group-lg>.btn,.btn-lg{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.btn-group-sm>.btn,.btn-sm{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:.5rem}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;transition:opacity .15s linear}.fade.show{opacity:1}.collapse{display:none}.collapse.show{display:block}tr.collapse.show{display:table-row}tbody.collapse.show{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;transition:height .35s ease}.dropdown,.dropup{position:relative}.dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:10rem;padding:.5rem 0;margin:.125rem 0 0;font-size:1rem;color:#212529;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropup .dropdown-menu{margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-menu{margin-top:0;margin-left:.125rem}.dropright .dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-bottom:.3em solid transparent;border-left:.3em solid}.dropright .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-toggle::after{vertical-align:0}.dropleft .dropdown-menu{margin-top:0;margin-right:.125rem}.dropleft .dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:""}.dropleft .dropdown-toggle::after{display:none}.dropleft .dropdown-toggle::before{display:inline-block;width:0;height:0;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropleft .dropdown-toggle:empty::after{margin-left:0}.dropleft .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid #e9ecef}.dropdown-item{display:block;width:100%;padding:.25rem 1.5rem;clear:both;font-weight:400;color:#212529;text-align:inherit;white-space:nowrap;background-color:transparent;border:0}.dropdown-item:focus,.dropdown-item:hover{color:#16181b;text-decoration:none;background-color:#f8f9fa}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#007bff}.dropdown-item.disabled,.dropdown-item:disabled{color:#6c757d;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1.5rem;margin-bottom:0;font-size:.875rem;color:#6c757d;white-space:nowrap}.btn-group,.btn-group-vertical{position:relative;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;-webkit-box-flex:0;-ms-flex:0 1 auto;flex:0 1 auto}.btn-group-vertical>.btn:hover,.btn-group>.btn:hover{z-index:1}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus{z-index:1}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group,.btn-group-vertical .btn+.btn,.btn-group-vertical .btn+.btn-group,.btn-group-vertical .btn-group+.btn,.btn-group-vertical .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after{margin-left:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.btn-group-vertical .btn,.btn-group-vertical .btn-group{width:100%}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn:not(:first-child){border-top-left-radius:0;border-top-right-radius:0}.btn-group-toggle>.btn,.btn-group-toggle>.btn-group>.btn{margin-bottom:0}.btn-group-toggle>.btn input[type=checkbox],.btn-group-toggle>.btn input[type=radio],.btn-group-toggle>.btn-group>.btn input[type=checkbox],.btn-group-toggle>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-align:stretch;-ms-flex-align:stretch;align-items:stretch;width:100%}.input-group>.custom-file,.input-group>.custom-select,.input-group>.form-control{position:relative;-webkit-box-flex:1;-ms-flex:1 1 auto;flex:1 1 auto;width:1%;margin-bottom:0}.input-group>.custom-file:focus,.input-group>.custom-select:focus,.input-group>.form-control:focus{z-index:3}.input-group>.custom-file+.custom-file,.input-group>.custom-file+.custom-select,.input-group>.custom-file+.form-control,.input-group>.custom-select+.custom-file,.input-group>.custom-select+.custom-select,.input-group>.custom-select+.form-control,.input-group>.form-control+.custom-file,.input-group>.form-control+.custom-select,.input-group>.form-control+.form-control{margin-left:-1px}.input-group>.custom-select:not(:last-child),.input-group>.form-control:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-select:not(:first-child),.input-group>.form-control:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.custom-file{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.input-group>.custom-file:not(:last-child) .custom-file-label,.input-group>.custom-file:not(:last-child) .custom-file-label::before{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-file:not(:first-child) .custom-file-label,.input-group>.custom-file:not(:first-child) .custom-file-label::before{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-append,.input-group-prepend{display:-webkit-box;display:-ms-flexbox;display:flex}.input-group-append .btn,.input-group-prepend .btn{position:relative;z-index:2}.input-group-append .btn+.btn,.input-group-append .btn+.input-group-text,.input-group-append .input-group-text+.btn,.input-group-append .input-group-text+.input-group-text,.input-group-prepend .btn+.btn,.input-group-prepend .btn+.input-group-text,.input-group-prepend .input-group-text+.btn,.input-group-prepend .input-group-text+.input-group-text{margin-left:-1px}.input-group-prepend{margin-right:-1px}.input-group-append{margin-left:-1px}.input-group-text{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:.375rem .75rem;margin-bottom:0;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;text-align:center;white-space:nowrap;background-color:#e9ecef;border:1px solid #ced4da;border-radius:.25rem}.input-group-text input[type=checkbox],.input-group-text input[type=radio]{margin-top:0}.input-group>.input-group-append:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group>.input-group-append:last-child>.input-group-text:not(:last-child),.input-group>.input-group-append:not(:last-child)>.btn,.input-group>.input-group-append:not(:last-child)>.input-group-text,.input-group>.input-group-prepend>.btn,.input-group>.input-group-prepend>.input-group-text{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.input-group-append>.btn,.input-group>.input-group-append>.input-group-text,.input-group>.input-group-prepend:first-child>.btn:not(:first-child),.input-group>.input-group-prepend:first-child>.input-group-text:not(:first-child),.input-group>.input-group-prepend:not(:first-child)>.btn,.input-group>.input-group-prepend:not(:first-child)>.input-group-text{border-top-left-radius:0;border-bottom-left-radius:0}.custom-control{position:relative;display:block;min-height:1.5rem;padding-left:1.5rem}.custom-control-inline{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;margin-right:1rem}.custom-control-input{position:absolute;z-index:-1;opacity:0}.custom-control-input:checked~ .custom-control-label::before{color:#fff;background-color:#007bff}.custom-control-input:focus~ .custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-control-input:active~ .custom-control-label::before{color:#fff;background-color:#b3d7ff}.custom-control-input:disabled~.custom-control-label{color:#6c757d}.custom-control-input:disabled~ .custom-control-label::before{background-color:#e9ecef}.custom-control-label{margin-bottom:0} .custom-control-label::before{position:absolute;top:.25rem;left:0;display:block;width:0rem;height:0rem;pointer-events:none;content:"";-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:#dee2e6}.custom-control-label::after{position:absolute;top:.25rem;left:0;display:block;width:1rem;height:1rem;content:"";background-repeat:no-repeat;background-position:center center;background-size:50% 50%}.custom-checkbox .custom-control-label::before{border-radius:.25rem}.custom-checkbox .custom-control-input:checked~ .custom-control-label::before{background-color:#007bff}.custom-checkbox .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3E%3C/svg%3E")}.custom-checkbox .custom-control-input:indeterminate~ .custom-control-label::before{background-color:#007bff}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::after{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3E%3Cpath stroke='%23fff' d='M0 2h4'/%3E%3C/svg%3E")}.custom-checkbox .custom-control-input:disabled:checked~ .custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-checkbox .custom-control-input:disabled:indeterminate~ .custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-radio .custom-control-label::before{border-radius:50%}.custom-radio .custom-control-input:checked~ .custom-control-label::before{background-color:#007bff}.custom-radio .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3E%3Ccircle r='3' fill='%23fff'/%3E%3C/svg%3E")}.custom-radio .custom-control-input:disabled:checked~ .custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-select{display:inline-block;width:100%;height:calc(2.25rem + 2px);padding:.375rem 1.75rem .375rem .75rem;line-height:1.5;color:#495057;vertical-align:middle;background:#fff url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") no-repeat right .75rem center;background-size:8px 10px;border:1px solid #ced4da;border-radius:.25rem;-webkit-appearance:none;-moz-appearance:none;appearance:none}.custom-select:focus{border-color:#80bdff;outline:0;box-shadow:inset 0 1px 2px rgba(0,0,0,.075),0 0 5px rgba(128,189,255,.5)}.custom-select:focus::-ms-value{color:#495057;background-color:#fff}.custom-select[multiple],.custom-select[size]:not([size="1"]){height:auto;padding-right:.75rem;background-image:none}.custom-select:disabled{color:#6c757d;background-color:#e9ecef}.custom-select::-ms-expand{opacity:0}.custom-select-sm{height:calc(1.8125rem + 2px);padding-top:.375rem;padding-bottom:.375rem;font-size:75%}.custom-select-lg{height:calc(2.875rem + 2px);padding-top:.375rem;padding-bottom:.375rem;font-size:125%}.custom-file{position:relative;display:inline-block;width:100%;height:calc(2.25rem + 2px);margin-bottom:0}.custom-file-input{position:relative;z-index:2;width:100%;height:calc(2.25rem + 2px);margin:0;opacity:0}.custom-file-input:focus~.custom-file-control{border-color:#80bdff;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.custom-file-input:focus~.custom-file-control::before{border-color:#80bdff}.custom-file-input:lang(en)~.custom-file-label::after{content:"Browse"}.custom-file-label{position:absolute;top:0;right:0;left:0;z-index:1;height:calc(2.25rem + 2px);padding:.375rem .75rem;line-height:1.5;color:#495057;background-color:#fff;border:1px solid #ced4da;border-radius:.25rem}.custom-file-label::after{position:absolute;top:0;right:0;bottom:0;z-index:3;display:block;height:calc(calc(2.25rem + 2px) - 1px * 2);padding:.375rem .75rem;line-height:1.5;color:#495057;content:"Browse";background-color:#e9ecef;border-left:1px solid #ced4da;border-radius:0 .25rem .25rem 0}.nav{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem}.nav-link:focus,.nav-link:hover{text-decoration:none}.nav-link.disabled{color:#6c757d}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-item{margin-bottom:-1px}.nav-tabs .nav-link{border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#e9ecef #e9ecef #dee2e6}.nav-tabs .nav-link.disabled{color:#6c757d;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:#495057;background-color:#fff;border-color:#dee2e6 #dee2e6 #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{border-radius:.25rem}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background-color:#007bff}.nav-fill .nav-item{-webkit-box-flex:1;-ms-flex:1 1 auto;flex:1 1 auto;text-align:center}.nav-justified .nav-item{-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;text-align:center}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;padding:.5rem 1rem}.navbar>.container,.navbar>.container-fluid{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.navbar-brand{display:inline-block;padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;line-height:inherit;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-nav{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static;float:none}.navbar-text{display:inline-block;padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{-ms-flex-preferred-size:100%;flex-basis:100%;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:1.25rem;line-height:1;background-color:transparent;border:1px solid transparent;border-radius:.25rem}.navbar-toggler:focus,.navbar-toggler:hover{text-decoration:none}.navbar-toggler:not(:disabled):not(.disabled){cursor:pointer}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;content:"";background:no-repeat center center;background-size:100% 100%}@media (max-width:575.98px){.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:576px){.navbar-expand-sm{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-sm .navbar-nav{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-sm .navbar-collapse{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .dropup .dropdown-menu{top:auto;bottom:100%}}@media (max-width:767.98px){.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:768px){.navbar-expand-md{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-md .navbar-nav{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-md .navbar-collapse{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .dropup .dropdown-menu{top:auto;bottom:100%}}@media (max-width:991.98px){.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:992px){.navbar-expand-lg{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-lg .navbar-nav{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-lg .navbar-collapse{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .dropup .dropdown-menu{top:auto;bottom:100%}}@media (max-width:1199.98px){.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:1200px){.navbar-expand-xl{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-xl .navbar-nav{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-xl .navbar-collapse{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .dropup .dropdown-menu{top:auto;bottom:100%}}.navbar-expand{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand>.container,.navbar-expand>.container-fluid{padding-right:0;padding-left:0}.navbar-expand .navbar-nav{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand>.container,.navbar-expand>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand .navbar-collapse{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .dropup .dropdown-menu{top:auto;bottom:100%}.navbar-light .navbar-brand{color:rgba(0,0,0,.9)}.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:rgba(0,0,0,.9)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.5)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(0,0,0,.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .active>.nav-link,.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .nav-link.show,.navbar-light .navbar-nav .show>.nav-link{color:rgba(0,0,0,.9)}.navbar-light .navbar-toggler{color:rgba(0,0,0,.5);border-color:rgba(0,0,0,.1)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(0, 0, 0, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E")}.navbar-light .navbar-text{color:rgba(0,0,0,.5)}.navbar-light .navbar-text a{color:rgba(0,0,0,.9)}.navbar-light .navbar-text a:focus,.navbar-light .navbar-text a:hover{color:rgba(0,0,0,.9)}.navbar-dark .navbar-brand{color:#fff}.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover{color:#fff}.navbar-dark .navbar-nav .nav-link{color:rgba(255,255,255,.5)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:rgba(255,255,255,.75)}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(255,255,255,.25)}.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .nav-link.show,.navbar-dark .navbar-nav .show>.nav-link{color:#fff}.navbar-dark .navbar-toggler{color:rgba(255,255,255,.5);border-color:rgba(255,255,255,.1)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(255, 255, 255, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E")}.navbar-dark .navbar-text{color:rgba(255,255,255,.5)}.navbar-dark .navbar-text a{color:#fff}.navbar-dark .navbar-text a:focus,.navbar-dark .navbar-text a:hover{color:#fff}.card{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.card>hr{margin-right:0;margin-left:0}.card>.list-group:first-child .list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card>.list-group:last-child .list-group-item:last-child{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.card-body{-webkit-box-flex:1;-ms-flex:1 1 auto;flex:1 1 auto;padding:1.25rem}.card-title{margin-bottom:.75rem}.card-subtitle{margin-top:-.375rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1.25rem}.card-header{padding:.75rem 1.25rem;margin-bottom:0;background-color:rgba(0,0,0,.03);border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-header+.list-group .list-group-item:first-child{border-top:0}.card-footer{padding:.75rem 1.25rem;background-color:rgba(0,0,0,.03);border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{margin-right:-.625rem;margin-bottom:-.75rem;margin-left:-.625rem;border-bottom:0}.card-header-pills{margin-right:-.625rem;margin-left:-.625rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1.25rem}.card-img{width:100%;border-radius:calc(.25rem - 1px)}.card-img-top{width:100%;border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img-bottom{width:100%;border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-deck{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.card-deck .card{margin-bottom:15px}@media (min-width:576px){.card-deck{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row wrap;flex-flow:row wrap;margin-right:-15px;margin-left:-15px}.card-deck .card{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-flex:1;-ms-flex:1 0 0%;flex:1 0 0%;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;margin-right:15px;margin-bottom:0;margin-left:15px}}.card-group{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.card-group>.card{margin-bottom:15px}@media (min-width:576px){.card-group{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row wrap;flex-flow:row wrap}.card-group>.card{-webkit-box-flex:1;-ms-flex:1 0 0%;flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:first-child{border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:first-child .card-header,.card-group>.card:first-child .card-img-top{border-top-right-radius:0}.card-group>.card:first-child .card-footer,.card-group>.card:first-child .card-img-bottom{border-bottom-right-radius:0}.card-group>.card:last-child{border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:last-child .card-header,.card-group>.card:last-child .card-img-top{border-top-left-radius:0}.card-group>.card:last-child .card-footer,.card-group>.card:last-child .card-img-bottom{border-bottom-left-radius:0}.card-group>.card:only-child{border-radius:.25rem}.card-group>.card:only-child .card-header,.card-group>.card:only-child .card-img-top{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card-group>.card:only-child .card-footer,.card-group>.card:only-child .card-img-bottom{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.card-group>.card:not(:first-child):not(:last-child):not(:only-child){border-radius:0}.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-footer,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-header,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-img-bottom,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-img-top{border-radius:0}}.card-columns .card{margin-bottom:.75rem}@media (min-width:576px){.card-columns{-webkit-column-count:3;-moz-column-count:3;column-count:3;-webkit-column-gap:1.25rem;-moz-column-gap:1.25rem;column-gap:1.25rem}.card-columns .card{display:inline-block;width:100%}}.breadcrumb{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding:.75rem 1rem;margin-bottom:1rem;list-style:none;background-color:#e9ecef;border-radius:.25rem}.breadcrumb-item+.breadcrumb-item::before{display:inline-block;padding-right:.5rem;padding-left:.5rem;color:#6c757d;content:"/"}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:underline}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:none}.breadcrumb-item.active{color:#6c757d}.pagination{display:-webkit-box;display:-ms-flexbox;display:flex;padding-left:0;list-style:none;border-radius:.25rem}.page-link{position:relative;display:block;padding:.5rem .75rem;margin-left:-1px;line-height:1.25;color:#007bff;background-color:#fff;border:1px solid #dee2e6}.page-link:hover{color:#0056b3;text-decoration:none;background-color:#e9ecef;border-color:#dee2e6}.page-link:focus{z-index:2;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.page-link:not(:disabled):not(.disabled){cursor:pointer}.page-item:first-child .page-link{margin-left:0;border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.page-item.active .page-link{z-index:1;color:#fff;background-color:#007bff;border-color:#007bff}.page-item.disabled .page-link{color:#6c757d;pointer-events:none;cursor:auto;background-color:#fff;border-color:#dee2e6}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem;line-height:1.5}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:.875rem;line-height:1.5}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.badge{display:inline-block;padding:.25em .4em;font-size:75%;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.badge-pill{padding-right:.6em;padding-left:.6em;border-radius:10rem}.badge-primary{color:#fff;background-color:#007bff}.badge-primary[href]:focus,.badge-primary[href]:hover{color:#fff;text-decoration:none;background-color:#0062cc}.badge-secondary{color:#fff;background-color:#6c757d}.badge-secondary[href]:focus,.badge-secondary[href]:hover{color:#fff;text-decoration:none;background-color:#545b62}.badge-success{color:#fff;background-color:#28a745}.badge-success[href]:focus,.badge-success[href]:hover{color:#fff;text-decoration:none;background-color:#1e7e34}.badge-info{color:#fff;background-color:#17a2b8}.badge-info[href]:focus,.badge-info[href]:hover{color:#fff;text-decoration:none;background-color:#117a8b}.badge-warning{color:#212529;background-color:#ffc107}.badge-warning[href]:focus,.badge-warning[href]:hover{color:#212529;text-decoration:none;background-color:#d39e00}.badge-danger{color:#fff;background-color:#dc3545}.badge-danger[href]:focus,.badge-danger[href]:hover{color:#fff;text-decoration:none;background-color:#bd2130}.badge-light{color:#212529;background-color:#f8f9fa}.badge-light[href]:focus,.badge-light[href]:hover{color:#212529;text-decoration:none;background-color:#dae0e5}.badge-dark{color:#fff;background-color:#343a40}.badge-dark[href]:focus,.badge-dark[href]:hover{color:#fff;text-decoration:none;background-color:#1d2124}.jumbotron{padding:2rem 1rem;margin-bottom:2rem;background-color:#e9ecef;border-radius:.3rem}@media (min-width:576px){.jumbotron{padding:4rem 2rem}}.jumbotron-fluid{padding-right:0;padding-left:0;border-radius:0}.alert{position:relative;padding:.75rem 1.25rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:4rem}.alert-dismissible .close{position:absolute;top:0;right:0;padding:.75rem 1.25rem;color:inherit}.alert-primary{color:#004085;background-color:#cce5ff;border-color:#b8daff}.alert-primary hr{border-top-color:#9fcdff}.alert-primary .alert-link{color:#002752}.alert-secondary{color:#383d41;background-color:#e2e3e5;border-color:#d6d8db}.alert-secondary hr{border-top-color:#c8cbcf}.alert-secondary .alert-link{color:#202326}.alert-success{color:#155724;background-color:#d4edda;border-color:#c3e6cb}.alert-success hr{border-top-color:#b1dfbb}.alert-success .alert-link{color:#0b2e13}.alert-info{color:#0c5460;background-color:#d1ecf1;border-color:#bee5eb}.alert-info hr{border-top-color:#abdde5}.alert-info .alert-link{color:#062c33}.alert-warning{color:#856404;background-color:#fff3cd;border-color:#ffeeba}.alert-warning hr{border-top-color:#ffe8a1}.alert-warning .alert-link{color:#533f03}.alert-danger{color:#721c24;background-color:#f8d7da;border-color:#f5c6cb}.alert-danger hr{border-top-color:#f1b0b7}.alert-danger .alert-link{color:#491217}.alert-light{color:#818182;background-color:#fefefe;border-color:#fdfdfe}.alert-light hr{border-top-color:#ececf6}.alert-light .alert-link{color:#686868}.alert-dark{color:#1b1e21;background-color:#d6d8d9;border-color:#c6c8ca}.alert-dark hr{border-top-color:#b9bbbe}.alert-dark .alert-link{color:#040505}@-webkit-keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}.progress{display:-webkit-box;display:-ms-flexbox;display:flex;height:1rem;overflow:hidden;font-size:.75rem;background-color:#e9ecef;border-radius:.25rem}.progress-bar{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;color:#fff;text-align:center;background-color:#007bff;transition:width .6s ease}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}.progress-bar-animated{-webkit-animation:progress-bar-stripes 1s linear infinite;animation:progress-bar-stripes 1s linear infinite}.media{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start}.media-body{-webkit-box-flex:1;-ms-flex:1;flex:1}.list-group{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0}.list-group-item-action{width:100%;color:#495057;text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{color:#495057;text-decoration:none;background-color:#f8f9fa}.list-group-item-action:active{color:#212529;background-color:#e9ecef}.list-group-item{position:relative;display:block;padding:.75rem 1.25rem;margin-bottom:-1px;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.list-group-item:focus,.list-group-item:hover{z-index:1;text-decoration:none}.list-group-item.disabled,.list-group-item:disabled{color:#6c757d;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#007bff;border-color:#007bff}.list-group-flush .list-group-item{border-right:0;border-left:0;border-radius:0}.list-group-flush:first-child .list-group-item:first-child{border-top:0}.list-group-flush:last-child .list-group-item:last-child{border-bottom:0}.list-group-item-primary{color:#004085;background-color:#b8daff}.list-group-item-primary.list-group-item-action:focus,.list-group-item-primary.list-group-item-action:hover{color:#004085;background-color:#9fcdff}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#004085;border-color:#004085}.list-group-item-secondary{color:#383d41;background-color:#d6d8db}.list-group-item-secondary.list-group-item-action:focus,.list-group-item-secondary.list-group-item-action:hover{color:#383d41;background-color:#c8cbcf}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#383d41;border-color:#383d41}.list-group-item-success{color:#155724;background-color:#c3e6cb}.list-group-item-success.list-group-item-action:focus,.list-group-item-success.list-group-item-action:hover{color:#155724;background-color:#b1dfbb}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#155724;border-color:#155724}.list-group-item-info{color:#0c5460;background-color:#bee5eb}.list-group-item-info.list-group-item-action:focus,.list-group-item-info.list-group-item-action:hover{color:#0c5460;background-color:#abdde5}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#0c5460;border-color:#0c5460}.list-group-item-warning{color:#856404;background-color:#ffeeba}.list-group-item-warning.list-group-item-action:focus,.list-group-item-warning.list-group-item-action:hover{color:#856404;background-color:#ffe8a1}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#856404;border-color:#856404}.list-group-item-danger{color:#721c24;background-color:#f5c6cb}.list-group-item-danger.list-group-item-action:focus,.list-group-item-danger.list-group-item-action:hover{color:#721c24;background-color:#f1b0b7}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#721c24;border-color:#721c24}.list-group-item-light{color:#818182;background-color:#fdfdfe}.list-group-item-light.list-group-item-action:focus,.list-group-item-light.list-group-item-action:hover{color:#818182;background-color:#ececf6}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#818182;border-color:#818182}.list-group-item-dark{color:#1b1e21;background-color:#c6c8ca}.list-group-item-dark.list-group-item-action:focus,.list-group-item-dark.list-group-item-action:hover{color:#1b1e21;background-color:#b9bbbe}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#1b1e21;border-color:#1b1e21}.close{float:right;font-size:1.5rem;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.5}.close:focus,.close:hover{color:#000;text-decoration:none;opacity:.75}.close:not(:disabled):not(.disabled){cursor:pointer}button.close{padding:0;background-color:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;outline:0}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:-webkit-transform .3s ease-out;transition:transform .3s ease-out;transition:transform .3s ease-out,-webkit-transform .3s ease-out;-webkit-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.show .modal-dialog{-webkit-transform:translate(0,0);transform:translate(0,0)}.modal-dialog-centered{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;min-height:calc(100% - (.5rem * 2))}.modal-content{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;padding:1rem;border-bottom:1px solid #e9ecef;border-top-left-radius:.3rem;border-top-right-radius:.3rem}.modal-header .close{padding:1rem;margin:-1rem -1rem -1rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;-webkit-box-flex:1;-ms-flex:1 1 auto;flex:1 1 auto;padding:1rem}.modal-footer{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end;padding:1rem;border-top:1px solid #e9ecef}.modal-footer>:not(:first-child){margin-left:.25rem}.modal-footer>:not(:last-child){margin-right:.25rem}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-centered{min-height:calc(100% - (1.75rem * 2))}.modal-sm{max-width:300px}}@media (min-width:992px){.modal-lg{max-width:800px}}.tooltip{position:absolute;z-index:1070;display:block;margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[x-placement^=top],.bs-tooltip-top{padding:.4rem 0}.bs-tooltip-auto[x-placement^=top] .arrow,.bs-tooltip-top .arrow{bottom:0}.bs-tooltip-auto[x-placement^=top] .arrow::before,.bs-tooltip-top .arrow::before{top:0;border-width:.4rem .4rem 0;border-top-color:#000}.bs-tooltip-auto[x-placement^=right],.bs-tooltip-right{padding:0 .4rem}.bs-tooltip-auto[x-placement^=right] .arrow,.bs-tooltip-right .arrow{left:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=right] .arrow::before,.bs-tooltip-right .arrow::before{right:0;border-width:.4rem .4rem .4rem 0;border-right-color:#000}.bs-tooltip-auto[x-placement^=bottom],.bs-tooltip-bottom{padding:.4rem 0}.bs-tooltip-auto[x-placement^=bottom] .arrow,.bs-tooltip-bottom .arrow{top:0}.bs-tooltip-auto[x-placement^=bottom] .arrow::before,.bs-tooltip-bottom .arrow::before{bottom:0;border-width:0 .4rem .4rem;border-bottom-color:#000}.bs-tooltip-auto[x-placement^=left],.bs-tooltip-left{padding:0 .4rem}.bs-tooltip-auto[x-placement^=left] .arrow,.bs-tooltip-left .arrow{right:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=left] .arrow::before,.bs-tooltip-left .arrow::before{left:0;border-width:.4rem 0 .4rem .4rem;border-left-color:#000}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.popover{position:absolute;top:0;left:0;z-index:1060;display:block;max-width:276px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover .arrow{position:absolute;display:block;width:1rem;height:.5rem;margin:0 .3rem}.popover .arrow::after,.popover .arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid}.bs-popover-auto[x-placement^=top],.bs-popover-top{margin-bottom:.5rem}.bs-popover-auto[x-placement^=top] .arrow,.bs-popover-top .arrow{bottom:calc((.5rem + 1px) * -1)}.bs-popover-auto[x-placement^=top] .arrow::after,.bs-popover-auto[x-placement^=top] .arrow::before,.bs-popover-top .arrow::after,.bs-popover-top .arrow::before{border-width:.5rem .5rem 0}.bs-popover-auto[x-placement^=top] .arrow::before,.bs-popover-top .arrow::before{bottom:0;border-top-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=top] .arrow::after,.bs-popover-top .arrow::after{bottom:1px;border-top-color:#fff}.bs-popover-auto[x-placement^=right],.bs-popover-right{margin-left:.5rem}.bs-popover-auto[x-placement^=right] .arrow,.bs-popover-right .arrow{left:calc((.5rem + 1px) * -1);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=right] .arrow::after,.bs-popover-auto[x-placement^=right] .arrow::before,.bs-popover-right .arrow::after,.bs-popover-right .arrow::before{border-width:.5rem .5rem .5rem 0}.bs-popover-auto[x-placement^=right] .arrow::before,.bs-popover-right .arrow::before{left:0;border-right-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=right] .arrow::after,.bs-popover-right .arrow::after{left:1px;border-right-color:#fff}.bs-popover-auto[x-placement^=bottom],.bs-popover-bottom{margin-top:.5rem}.bs-popover-auto[x-placement^=bottom] .arrow,.bs-popover-bottom .arrow{top:calc((.5rem + 1px) * -1)}.bs-popover-auto[x-placement^=bottom] .arrow::after,.bs-popover-auto[x-placement^=bottom] .arrow::before,.bs-popover-bottom .arrow::after,.bs-popover-bottom .arrow::before{border-width:0 .5rem .5rem .5rem}.bs-popover-auto[x-placement^=bottom] .arrow::before,.bs-popover-bottom .arrow::before{top:0;border-bottom-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=bottom] .arrow::after,.bs-popover-bottom .arrow::after{top:1px;border-bottom-color:#fff}.bs-popover-auto[x-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-.5rem;content:"";border-bottom:1px solid #f7f7f7}.bs-popover-auto[x-placement^=left],.bs-popover-left{margin-right:.5rem}.bs-popover-auto[x-placement^=left] .arrow,.bs-popover-left .arrow{right:calc((.5rem + 1px) * -1);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=left] .arrow::after,.bs-popover-auto[x-placement^=left] .arrow::before,.bs-popover-left .arrow::after,.bs-popover-left .arrow::before{border-width:.5rem 0 .5rem .5rem}.bs-popover-auto[x-placement^=left] .arrow::before,.bs-popover-left .arrow::before{right:0;border-left-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=left] .arrow::after,.bs-popover-left .arrow::after{right:1px;border-left-color:#fff}.popover-header{padding:.5rem .75rem;margin-bottom:0;font-size:1rem;color:inherit;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:.5rem .75rem;color:#212529}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-item{position:relative;display:none;-webkit-box-align:center;-ms-flex-align:center;align-items:center;width:100%;transition:-webkit-transform .6s ease;transition:transform .6s ease;transition:transform .6s ease,-webkit-transform .6s ease;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.carousel-item-next,.carousel-item-prev{position:absolute;top:0}.carousel-item-next.carousel-item-left,.carousel-item-prev.carousel-item-right{-webkit-transform:translateX(0);transform:translateX(0)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.carousel-item-next.carousel-item-left,.carousel-item-prev.carousel-item-right{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.active.carousel-item-right,.carousel-item-next{-webkit-transform:translateX(100%);transform:translateX(100%)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.active.carousel-item-right,.carousel-item-next{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}.active.carousel-item-left,.carousel-item-prev{-webkit-transform:translateX(-100%);transform:translateX(-100%)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.active.carousel-item-left,.carousel-item-prev{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;width:15%;color:#fff;text-align:center;opacity:.5}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:20px;height:20px;background:transparent no-repeat center center;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M5.25 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3E%3C/svg%3E")}.carousel-control-next-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M2.75 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3E%3C/svg%3E")}.carousel-indicators{position:absolute;right:0;bottom:10px;left:0;z-index:15;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;padding-left:0;margin-right:15%;margin-left:15%;list-style:none}.carousel-indicators li{position:relative;-webkit-box-flex:0;-ms-flex:0 1 auto;flex:0 1 auto;width:30px;height:3px;margin-right:3px;margin-left:3px;text-indent:-999px;background-color:rgba(255,255,255,.5)}.carousel-indicators li::before{position:absolute;top:-10px;left:0;display:inline-block;width:100%;height:10px;content:""}.carousel-indicators li::after{position:absolute;bottom:-10px;left:0;display:inline-block;width:100%;height:10px;content:""}.carousel-indicators .active{background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.bg-primary{background-color:#007bff!important}a.bg-primary:focus,a.bg-primary:hover,button.bg-primary:focus,button.bg-primary:hover{background-color:#0062cc!important}.bg-secondary{background-color:#6c757d!important}a.bg-secondary:focus,a.bg-secondary:hover,button.bg-secondary:focus,button.bg-secondary:hover{background-color:#545b62!important}.bg-success{background-color:#28a745!important}a.bg-success:focus,a.bg-success:hover,button.bg-success:focus,button.bg-success:hover{background-color:#1e7e34!important}.bg-info{background-color:#17a2b8!important}a.bg-info:focus,a.bg-info:hover,button.bg-info:focus,button.bg-info:hover{background-color:#117a8b!important}.bg-warning{background-color:#ffc107!important}a.bg-warning:focus,a.bg-warning:hover,button.bg-warning:focus,button.bg-warning:hover{background-color:#d39e00!important}.bg-danger{background-color:#dc3545!important}a.bg-danger:focus,a.bg-danger:hover,button.bg-danger:focus,button.bg-danger:hover{background-color:#bd2130!important}.bg-light{background-color:#f8f9fa!important}a.bg-light:focus,a.bg-light:hover,button.bg-light:focus,button.bg-light:hover{background-color:#dae0e5!important}.bg-dark{background-color:#343a40!important}a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover{background-color:#1d2124!important}.bg-white{background-color:#fff!important}.bg-transparent{background-color:transparent!important}.border{border:1px solid #dee2e6!important}.border-top{border-top:1px solid #dee2e6!important}.border-right{border-right:1px solid #dee2e6!important}.border-bottom{border-bottom:1px solid #dee2e6!important}.border-left{border-left:1px solid #dee2e6!important}.border-0{border:0!important}.border-top-0{border-top:0!important}.border-right-0{border-right:0!important}.border-bottom-0{border-bottom:0!important}.border-left-0{border-left:0!important}.border-primary{border-color:#007bff!important}.border-secondary{border-color:#6c757d!important}.border-success{border-color:#28a745!important}.border-info{border-color:#17a2b8!important}.border-warning{border-color:#ffc107!important}.border-danger{border-color:#dc3545!important}.border-light{border-color:#f8f9fa!important}.border-dark{border-color:#343a40!important}.border-white{border-color:#fff!important}.rounded{border-radius:.25rem!important}.rounded-top{border-top-left-radius:.25rem!important;border-top-right-radius:.25rem!important}.rounded-right{border-top-right-radius:.25rem!important;border-bottom-right-radius:.25rem!important}.rounded-bottom{border-bottom-right-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-left{border-top-left-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-circle{border-radius:50%!important}.rounded-0{border-radius:0!important}.clearfix::after{display:block;clear:both;content:""}.d-none{display:none!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important}.d-inline-flex{display:-webkit-inline-box!important;display:-ms-inline-flexbox!important;display:inline-flex!important}@media (min-width:576px){.d-sm-none{display:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important}.d-sm-inline-flex{display:-webkit-inline-box!important;display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:768px){.d-md-none{display:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important}.d-md-inline-flex{display:-webkit-inline-box!important;display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:992px){.d-lg-none{display:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important}.d-lg-inline-flex{display:-webkit-inline-box!important;display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:1200px){.d-xl-none{display:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important}.d-xl-inline-flex{display:-webkit-inline-box!important;display:-ms-inline-flexbox!important;display:inline-flex!important}}@media print{.d-print-none{display:none!important}.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important}.d-print-inline-flex{display:-webkit-inline-box!important;display:-ms-inline-flexbox!important;display:inline-flex!important}}.embed-responsive{position:relative;display:block;width:100%;padding:0;overflow:hidden}.embed-responsive::before{display:block;content:""}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-21by9::before{padding-top:42.857143%}.embed-responsive-16by9::before{padding-top:56.25%}.embed-responsive-4by3::before{padding-top:75%}.embed-responsive-1by1::before{padding-top:100%}.flex-row{-webkit-box-orient:horizontal!important;-webkit-box-direction:normal!important;-ms-flex-direction:row!important;flex-direction:row!important}.flex-column{-webkit-box-orient:vertical!important;-webkit-box-direction:normal!important;-ms-flex-direction:column!important;flex-direction:column!important}.flex-row-reverse{-webkit-box-orient:horizontal!important;-webkit-box-direction:reverse!important;-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-column-reverse{-webkit-box-orient:vertical!important;-webkit-box-direction:reverse!important;-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-start{-webkit-box-pack:start!important;-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-end{-webkit-box-pack:end!important;-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-center{-webkit-box-pack:center!important;-ms-flex-pack:center!important;justify-content:center!important}.justify-content-between{-webkit-box-pack:justify!important;-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-start{-webkit-box-align:start!important;-ms-flex-align:start!important;align-items:flex-start!important}.align-items-end{-webkit-box-align:end!important;-ms-flex-align:end!important;align-items:flex-end!important}.align-items-center{-webkit-box-align:center!important;-ms-flex-align:center!important;align-items:center!important}.align-items-baseline{-webkit-box-align:baseline!important;-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-stretch{-webkit-box-align:stretch!important;-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}@media (min-width:576px){.flex-sm-row{-webkit-box-orient:horizontal!important;-webkit-box-direction:normal!important;-ms-flex-direction:row!important;flex-direction:row!important}.flex-sm-column{-webkit-box-orient:vertical!important;-webkit-box-direction:normal!important;-ms-flex-direction:column!important;flex-direction:column!important}.flex-sm-row-reverse{-webkit-box-orient:horizontal!important;-webkit-box-direction:reverse!important;-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-sm-column-reverse{-webkit-box-orient:vertical!important;-webkit-box-direction:reverse!important;-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-sm-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-sm-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-sm-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-sm-start{-webkit-box-pack:start!important;-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-sm-end{-webkit-box-pack:end!important;-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-sm-center{-webkit-box-pack:center!important;-ms-flex-pack:center!important;justify-content:center!important}.justify-content-sm-between{-webkit-box-pack:justify!important;-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-sm-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-sm-start{-webkit-box-align:start!important;-ms-flex-align:start!important;align-items:flex-start!important}.align-items-sm-end{-webkit-box-align:end!important;-ms-flex-align:end!important;align-items:flex-end!important}.align-items-sm-center{-webkit-box-align:center!important;-ms-flex-align:center!important;align-items:center!important}.align-items-sm-baseline{-webkit-box-align:baseline!important;-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-sm-stretch{-webkit-box-align:stretch!important;-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-sm-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-sm-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-sm-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-sm-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-sm-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-sm-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-sm-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-sm-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-sm-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-sm-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-sm-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-sm-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:768px){.flex-md-row{-webkit-box-orient:horizontal!important;-webkit-box-direction:normal!important;-ms-flex-direction:row!important;flex-direction:row!important}.flex-md-column{-webkit-box-orient:vertical!important;-webkit-box-direction:normal!important;-ms-flex-direction:column!important;flex-direction:column!important}.flex-md-row-reverse{-webkit-box-orient:horizontal!important;-webkit-box-direction:reverse!important;-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-md-column-reverse{-webkit-box-orient:vertical!important;-webkit-box-direction:reverse!important;-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-md-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-md-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-md-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-md-start{-webkit-box-pack:start!important;-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-md-end{-webkit-box-pack:end!important;-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-md-center{-webkit-box-pack:center!important;-ms-flex-pack:center!important;justify-content:center!important}.justify-content-md-between{-webkit-box-pack:justify!important;-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-md-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-md-start{-webkit-box-align:start!important;-ms-flex-align:start!important;align-items:flex-start!important}.align-items-md-end{-webkit-box-align:end!important;-ms-flex-align:end!important;align-items:flex-end!important}.align-items-md-center{-webkit-box-align:center!important;-ms-flex-align:center!important;align-items:center!important}.align-items-md-baseline{-webkit-box-align:baseline!important;-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-md-stretch{-webkit-box-align:stretch!important;-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-md-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-md-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-md-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-md-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-md-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-md-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-md-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-md-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-md-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-md-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-md-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-md-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:992px){.flex-lg-row{-webkit-box-orient:horizontal!important;-webkit-box-direction:normal!important;-ms-flex-direction:row!important;flex-direction:row!important}.flex-lg-column{-webkit-box-orient:vertical!important;-webkit-box-direction:normal!important;-ms-flex-direction:column!important;flex-direction:column!important}.flex-lg-row-reverse{-webkit-box-orient:horizontal!important;-webkit-box-direction:reverse!important;-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-lg-column-reverse{-webkit-box-orient:vertical!important;-webkit-box-direction:reverse!important;-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-lg-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-lg-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-lg-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-lg-start{-webkit-box-pack:start!important;-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-lg-end{-webkit-box-pack:end!important;-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-lg-center{-webkit-box-pack:center!important;-ms-flex-pack:center!important;justify-content:center!important}.justify-content-lg-between{-webkit-box-pack:justify!important;-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-lg-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-lg-start{-webkit-box-align:start!important;-ms-flex-align:start!important;align-items:flex-start!important}.align-items-lg-end{-webkit-box-align:end!important;-ms-flex-align:end!important;align-items:flex-end!important}.align-items-lg-center{-webkit-box-align:center!important;-ms-flex-align:center!important;align-items:center!important}.align-items-lg-baseline{-webkit-box-align:baseline!important;-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-lg-stretch{-webkit-box-align:stretch!important;-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-lg-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-lg-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-lg-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-lg-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-lg-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-lg-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-lg-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-lg-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-lg-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-lg-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-lg-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-lg-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:1200px){.flex-xl-row{-webkit-box-orient:horizontal!important;-webkit-box-direction:normal!important;-ms-flex-direction:row!important;flex-direction:row!important}.flex-xl-column{-webkit-box-orient:vertical!important;-webkit-box-direction:normal!important;-ms-flex-direction:column!important;flex-direction:column!important}.flex-xl-row-reverse{-webkit-box-orient:horizontal!important;-webkit-box-direction:reverse!important;-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-xl-column-reverse{-webkit-box-orient:vertical!important;-webkit-box-direction:reverse!important;-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-xl-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-xl-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-xl-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-xl-start{-webkit-box-pack:start!important;-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-xl-end{-webkit-box-pack:end!important;-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-xl-center{-webkit-box-pack:center!important;-ms-flex-pack:center!important;justify-content:center!important}.justify-content-xl-between{-webkit-box-pack:justify!important;-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-xl-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-xl-start{-webkit-box-align:start!important;-ms-flex-align:start!important;align-items:flex-start!important}.align-items-xl-end{-webkit-box-align:end!important;-ms-flex-align:end!important;align-items:flex-end!important}.align-items-xl-center{-webkit-box-align:center!important;-ms-flex-align:center!important;align-items:center!important}.align-items-xl-baseline{-webkit-box-align:baseline!important;-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-xl-stretch{-webkit-box-align:stretch!important;-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-xl-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-xl-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-xl-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-xl-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-xl-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-xl-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-xl-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-xl-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-xl-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-xl-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-xl-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-xl-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}.float-left{float:left!important}.float-right{float:right!important}.float-none{float:none!important}@media (min-width:576px){.float-sm-left{float:left!important}.float-sm-right{float:right!important}.float-sm-none{float:none!important}}@media (min-width:768px){.float-md-left{float:left!important}.float-md-right{float:right!important}.float-md-none{float:none!important}}@media (min-width:992px){.float-lg-left{float:left!important}.float-lg-right{float:right!important}.float-lg-none{float:none!important}}@media (min-width:1200px){.float-xl-left{float:left!important}.float-xl-right{float:right!important}.float-xl-none{float:none!important}}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}@supports ((position:-webkit-sticky) or (position:sticky)){.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}.sr-only{position:absolute;width:1px;height:1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;-webkit-clip-path:inset(50%);clip-path:inset(50%);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;overflow:visible;clip:auto;white-space:normal;-webkit-clip-path:none;clip-path:none}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.mw-100{max-width:100%!important}.mh-100{max-height:100%!important}.m-0{margin:0!important}.mt-0,.my-0{margin-top:0!important}.mr-0,.mx-0{margin-right:0!important}.mb-0,.my-0{margin-bottom:0!important}.ml-0,.mx-0{margin-left:0!important}.m-1{margin:.25rem!important}.mt-1,.my-1{margin-top:.25rem!important}.mr-1,.mx-1{margin-right:.25rem!important}.mb-1,.my-1{margin-bottom:.25rem!important}.ml-1,.mx-1{margin-left:.25rem!important}.m-2{margin:.5rem!important}.mt-2,.my-2{margin-top:.5rem!important}.mr-2,.mx-2{margin-right:.5rem!important}.mb-2,.my-2{margin-bottom:.5rem!important}.ml-2,.mx-2{margin-left:.5rem!important}.m-3{margin:1rem!important}.mt-3,.my-3{margin-top:1rem!important}.mr-3,.mx-3{margin-right:1rem!important}.mb-3,.my-3{margin-bottom:1rem!important}.ml-3,.mx-3{margin-left:1rem!important}.m-4{margin:1.5rem!important}.mt-4,.my-4{margin-top:1.5rem!important}.mr-4,.mx-4{margin-right:1.5rem!important}.mb-4,.my-4{margin-bottom:1.5rem!important}.ml-4,.mx-4{margin-left:1.5rem!important}.m-5{margin:3rem!important}.mt-5,.my-5{margin-top:3rem!important}.mr-5,.mx-5{margin-right:3rem!important}.mb-5,.my-5{margin-bottom:3rem!important}.ml-5,.mx-5{margin-left:3rem!important}.p-0{padding:0!important}.pt-0,.py-0{padding-top:0!important}.pr-0,.px-0{padding-right:0!important}.pb-0,.py-0{padding-bottom:0!important}.pl-0,.px-0{padding-left:0!important}.p-1{padding:.25rem!important}.pt-1,.py-1{padding-top:.25rem!important}.pr-1,.px-1{padding-right:.25rem!important}.pb-1,.py-1{padding-bottom:.25rem!important}.pl-1,.px-1{padding-left:.25rem!important}.p-2{padding:.5rem!important}.pt-2,.py-2{padding-top:.5rem!important}.pr-2,.px-2{padding-right:.5rem!important}.pb-2,.py-2{padding-bottom:.5rem!important}.pl-2,.px-2{padding-left:.5rem!important}.p-3{padding:1rem!important}.pt-3,.py-3{padding-top:1rem!important}.pr-3,.px-3{padding-right:1rem!important}.pb-3,.py-3{padding-bottom:1rem!important}.pl-3,.px-3{padding-left:1rem!important}.p-4{padding:1.5rem!important}.pt-4,.py-4{padding-top:1.5rem!important}.pr-4,.px-4{padding-right:1.5rem!important}.pb-4,.py-4{padding-bottom:1.5rem!important}.pl-4,.px-4{padding-left:1.5rem!important}.p-5{padding:3rem!important}.pt-5,.py-5{padding-top:3rem!important}.pr-5,.px-5{padding-right:3rem!important}.pb-5,.py-5{padding-bottom:3rem!important}.pl-5,.px-5{padding-left:3rem!important}.m-auto{margin:auto!important}.mt-auto,.my-auto{margin-top:auto!important}.mr-auto,.mx-auto{margin-right:auto!important}.mb-auto,.my-auto{margin-bottom:auto!important}.ml-auto,.mx-auto{margin-left:auto!important}@media (min-width:576px){.m-sm-0{margin:0!important}.mt-sm-0,.my-sm-0{margin-top:0!important}.mr-sm-0,.mx-sm-0{margin-right:0!important}.mb-sm-0,.my-sm-0{margin-bottom:0!important}.ml-sm-0,.mx-sm-0{margin-left:0!important}.m-sm-1{margin:.25rem!important}.mt-sm-1,.my-sm-1{margin-top:.25rem!important}.mr-sm-1,.mx-sm-1{margin-right:.25rem!important}.mb-sm-1,.my-sm-1{margin-bottom:.25rem!important}.ml-sm-1,.mx-sm-1{margin-left:.25rem!important}.m-sm-2{margin:.5rem!important}.mt-sm-2,.my-sm-2{margin-top:.5rem!important}.mr-sm-2,.mx-sm-2{margin-right:.5rem!important}.mb-sm-2,.my-sm-2{margin-bottom:.5rem!important}.ml-sm-2,.mx-sm-2{margin-left:.5rem!important}.m-sm-3{margin:1rem!important}.mt-sm-3,.my-sm-3{margin-top:1rem!important}.mr-sm-3,.mx-sm-3{margin-right:1rem!important}.mb-sm-3,.my-sm-3{margin-bottom:1rem!important}.ml-sm-3,.mx-sm-3{margin-left:1rem!important}.m-sm-4{margin:1.5rem!important}.mt-sm-4,.my-sm-4{margin-top:1.5rem!important}.mr-sm-4,.mx-sm-4{margin-right:1.5rem!important}.mb-sm-4,.my-sm-4{margin-bottom:1.5rem!important}.ml-sm-4,.mx-sm-4{margin-left:1.5rem!important}.m-sm-5{margin:3rem!important}.mt-sm-5,.my-sm-5{margin-top:3rem!important}.mr-sm-5,.mx-sm-5{margin-right:3rem!important}.mb-sm-5,.my-sm-5{margin-bottom:3rem!important}.ml-sm-5,.mx-sm-5{margin-left:3rem!important}.p-sm-0{padding:0!important}.pt-sm-0,.py-sm-0{padding-top:0!important}.pr-sm-0,.px-sm-0{padding-right:0!important}.pb-sm-0,.py-sm-0{padding-bottom:0!important}.pl-sm-0,.px-sm-0{padding-left:0!important}.p-sm-1{padding:.25rem!important}.pt-sm-1,.py-sm-1{padding-top:.25rem!important}.pr-sm-1,.px-sm-1{padding-right:.25rem!important}.pb-sm-1,.py-sm-1{padding-bottom:.25rem!important}.pl-sm-1,.px-sm-1{padding-left:.25rem!important}.p-sm-2{padding:.5rem!important}.pt-sm-2,.py-sm-2{padding-top:.5rem!important}.pr-sm-2,.px-sm-2{padding-right:.5rem!important}.pb-sm-2,.py-sm-2{padding-bottom:.5rem!important}.pl-sm-2,.px-sm-2{padding-left:.5rem!important}.p-sm-3{padding:1rem!important}.pt-sm-3,.py-sm-3{padding-top:1rem!important}.pr-sm-3,.px-sm-3{padding-right:1rem!important}.pb-sm-3,.py-sm-3{padding-bottom:1rem!important}.pl-sm-3,.px-sm-3{padding-left:1rem!important}.p-sm-4{padding:1.5rem!important}.pt-sm-4,.py-sm-4{padding-top:1.5rem!important}.pr-sm-4,.px-sm-4{padding-right:1.5rem!important}.pb-sm-4,.py-sm-4{padding-bottom:1.5rem!important}.pl-sm-4,.px-sm-4{padding-left:1.5rem!important}.p-sm-5{padding:3rem!important}.pt-sm-5,.py-sm-5{padding-top:3rem!important}.pr-sm-5,.px-sm-5{padding-right:3rem!important}.pb-sm-5,.py-sm-5{padding-bottom:3rem!important}.pl-sm-5,.px-sm-5{padding-left:3rem!important}.m-sm-auto{margin:auto!important}.mt-sm-auto,.my-sm-auto{margin-top:auto!important}.mr-sm-auto,.mx-sm-auto{margin-right:auto!important}.mb-sm-auto,.my-sm-auto{margin-bottom:auto!important}.ml-sm-auto,.mx-sm-auto{margin-left:auto!important}}@media (min-width:768px){.m-md-0{margin:0!important}.mt-md-0,.my-md-0{margin-top:0!important}.mr-md-0,.mx-md-0{margin-right:0!important}.mb-md-0,.my-md-0{margin-bottom:0!important}.ml-md-0,.mx-md-0{margin-left:0!important}.m-md-1{margin:.25rem!important}.mt-md-1,.my-md-1{margin-top:.25rem!important}.mr-md-1,.mx-md-1{margin-right:.25rem!important}.mb-md-1,.my-md-1{margin-bottom:.25rem!important}.ml-md-1,.mx-md-1{margin-left:.25rem!important}.m-md-2{margin:.5rem!important}.mt-md-2,.my-md-2{margin-top:.5rem!important}.mr-md-2,.mx-md-2{margin-right:.5rem!important}.mb-md-2,.my-md-2{margin-bottom:.5rem!important}.ml-md-2,.mx-md-2{margin-left:.5rem!important}.m-md-3{margin:1rem!important}.mt-md-3,.my-md-3{margin-top:1rem!important}.mr-md-3,.mx-md-3{margin-right:1rem!important}.mb-md-3,.my-md-3{margin-bottom:1rem!important}.ml-md-3,.mx-md-3{margin-left:1rem!important}.m-md-4{margin:1.5rem!important}.mt-md-4,.my-md-4{margin-top:1.5rem!important}.mr-md-4,.mx-md-4{margin-right:1.5rem!important}.mb-md-4,.my-md-4{margin-bottom:1.5rem!important}.ml-md-4,.mx-md-4{margin-left:1.5rem!important}.m-md-5{margin:3rem!important}.mt-md-5,.my-md-5{margin-top:3rem!important}.mr-md-5,.mx-md-5{margin-right:3rem!important}.mb-md-5,.my-md-5{margin-bottom:3rem!important}.ml-md-5,.mx-md-5{margin-left:3rem!important}.p-md-0{padding:0!important}.pt-md-0,.py-md-0{padding-top:0!important}.pr-md-0,.px-md-0{padding-right:0!important}.pb-md-0,.py-md-0{padding-bottom:0!important}.pl-md-0,.px-md-0{padding-left:0!important}.p-md-1{padding:.25rem!important}.pt-md-1,.py-md-1{padding-top:.25rem!important}.pr-md-1,.px-md-1{padding-right:.25rem!important}.pb-md-1,.py-md-1{padding-bottom:.25rem!important}.pl-md-1,.px-md-1{padding-left:.25rem!important}.p-md-2{padding:.5rem!important}.pt-md-2,.py-md-2{padding-top:.5rem!important}.pr-md-2,.px-md-2{padding-right:.5rem!important}.pb-md-2,.py-md-2{padding-bottom:.5rem!important}.pl-md-2,.px-md-2{padding-left:.5rem!important}.p-md-3{padding:1rem!important}.pt-md-3,.py-md-3{padding-top:1rem!important}.pr-md-3,.px-md-3{padding-right:1rem!important}.pb-md-3,.py-md-3{padding-bottom:1rem!important}.pl-md-3,.px-md-3{padding-left:1rem!important}.p-md-4{padding:1.5rem!important}.pt-md-4,.py-md-4{padding-top:1.5rem!important}.pr-md-4,.px-md-4{padding-right:1.5rem!important}.pb-md-4,.py-md-4{padding-bottom:1.5rem!important}.pl-md-4,.px-md-4{padding-left:1.5rem!important}.p-md-5{padding:3rem!important}.pt-md-5,.py-md-5{padding-top:3rem!important}.pr-md-5,.px-md-5{padding-right:3rem!important}.pb-md-5,.py-md-5{padding-bottom:3rem!important}.pl-md-5,.px-md-5{padding-left:3rem!important}.m-md-auto{margin:auto!important}.mt-md-auto,.my-md-auto{margin-top:auto!important}.mr-md-auto,.mx-md-auto{margin-right:auto!important}.mb-md-auto,.my-md-auto{margin-bottom:auto!important}.ml-md-auto,.mx-md-auto{margin-left:auto!important}}@media (min-width:992px){.m-lg-0{margin:0!important}.mt-lg-0,.my-lg-0{margin-top:0!important}.mr-lg-0,.mx-lg-0{margin-right:0!important}.mb-lg-0,.my-lg-0{margin-bottom:0!important}.ml-lg-0,.mx-lg-0{margin-left:0!important}.m-lg-1{margin:.25rem!important}.mt-lg-1,.my-lg-1{margin-top:.25rem!important}.mr-lg-1,.mx-lg-1{margin-right:.25rem!important}.mb-lg-1,.my-lg-1{margin-bottom:.25rem!important}.ml-lg-1,.mx-lg-1{margin-left:.25rem!important}.m-lg-2{margin:.5rem!important}.mt-lg-2,.my-lg-2{margin-top:.5rem!important}.mr-lg-2,.mx-lg-2{margin-right:.5rem!important}.mb-lg-2,.my-lg-2{margin-bottom:.5rem!important}.ml-lg-2,.mx-lg-2{margin-left:.5rem!important}.m-lg-3{margin:1rem!important}.mt-lg-3,.my-lg-3{margin-top:1rem!important}.mr-lg-3,.mx-lg-3{margin-right:1rem!important}.mb-lg-3,.my-lg-3{margin-bottom:1rem!important}.ml-lg-3,.mx-lg-3{margin-left:1rem!important}.m-lg-4{margin:1.5rem!important}.mt-lg-4,.my-lg-4{margin-top:1.5rem!important}.mr-lg-4,.mx-lg-4{margin-right:1.5rem!important}.mb-lg-4,.my-lg-4{margin-bottom:1.5rem!important}.ml-lg-4,.mx-lg-4{margin-left:1.5rem!important}.m-lg-5{margin:3rem!important}.mt-lg-5,.my-lg-5{margin-top:3rem!important}.mr-lg-5,.mx-lg-5{margin-right:3rem!important}.mb-lg-5,.my-lg-5{margin-bottom:3rem!important}.ml-lg-5,.mx-lg-5{margin-left:3rem!important}.p-lg-0{padding:0!important}.pt-lg-0,.py-lg-0{padding-top:0!important}.pr-lg-0,.px-lg-0{padding-right:0!important}.pb-lg-0,.py-lg-0{padding-bottom:0!important}.pl-lg-0,.px-lg-0{padding-left:0!important}.p-lg-1{padding:.25rem!important}.pt-lg-1,.py-lg-1{padding-top:.25rem!important}.pr-lg-1,.px-lg-1{padding-right:.25rem!important}.pb-lg-1,.py-lg-1{padding-bottom:.25rem!important}.pl-lg-1,.px-lg-1{padding-left:.25rem!important}.p-lg-2{padding:.5rem!important}.pt-lg-2,.py-lg-2{padding-top:.5rem!important}.pr-lg-2,.px-lg-2{padding-right:.5rem!important}.pb-lg-2,.py-lg-2{padding-bottom:.5rem!important}.pl-lg-2,.px-lg-2{padding-left:.5rem!important}.p-lg-3{padding:1rem!important}.pt-lg-3,.py-lg-3{padding-top:1rem!important}.pr-lg-3,.px-lg-3{padding-right:1rem!important}.pb-lg-3,.py-lg-3{padding-bottom:1rem!important}.pl-lg-3,.px-lg-3{padding-left:1rem!important}.p-lg-4{padding:1.5rem!important}.pt-lg-4,.py-lg-4{padding-top:1.5rem!important}.pr-lg-4,.px-lg-4{padding-right:1.5rem!important}.pb-lg-4,.py-lg-4{padding-bottom:1.5rem!important}.pl-lg-4,.px-lg-4{padding-left:1.5rem!important}.p-lg-5{padding:3rem!important}.pt-lg-5,.py-lg-5{padding-top:3rem!important}.pr-lg-5,.px-lg-5{padding-right:3rem!important}.pb-lg-5,.py-lg-5{padding-bottom:3rem!important}.pl-lg-5,.px-lg-5{padding-left:3rem!important}.m-lg-auto{margin:auto!important}.mt-lg-auto,.my-lg-auto{margin-top:auto!important}.mr-lg-auto,.mx-lg-auto{margin-right:auto!important}.mb-lg-auto,.my-lg-auto{margin-bottom:auto!important}.ml-lg-auto,.mx-lg-auto{margin-left:auto!important}}@media (min-width:1200px){.m-xl-0{margin:0!important}.mt-xl-0,.my-xl-0{margin-top:0!important}.mr-xl-0,.mx-xl-0{margin-right:0!important}.mb-xl-0,.my-xl-0{margin-bottom:0!important}.ml-xl-0,.mx-xl-0{margin-left:0!important}.m-xl-1{margin:.25rem!important}.mt-xl-1,.my-xl-1{margin-top:.25rem!important}.mr-xl-1,.mx-xl-1{margin-right:.25rem!important}.mb-xl-1,.my-xl-1{margin-bottom:.25rem!important}.ml-xl-1,.mx-xl-1{margin-left:.25rem!important}.m-xl-2{margin:.5rem!important}.mt-xl-2,.my-xl-2{margin-top:.5rem!important}.mr-xl-2,.mx-xl-2{margin-right:.5rem!important}.mb-xl-2,.my-xl-2{margin-bottom:.5rem!important}.ml-xl-2,.mx-xl-2{margin-left:.5rem!important}.m-xl-3{margin:1rem!important}.mt-xl-3,.my-xl-3{margin-top:1rem!important}.mr-xl-3,.mx-xl-3{margin-right:1rem!important}.mb-xl-3,.my-xl-3{margin-bottom:1rem!important}.ml-xl-3,.mx-xl-3{margin-left:1rem!important}.m-xl-4{margin:1.5rem!important}.mt-xl-4,.my-xl-4{margin-top:1.5rem!important}.mr-xl-4,.mx-xl-4{margin-right:1.5rem!important}.mb-xl-4,.my-xl-4{margin-bottom:1.5rem!important}.ml-xl-4,.mx-xl-4{margin-left:1.5rem!important}.m-xl-5{margin:3rem!important}.mt-xl-5,.my-xl-5{margin-top:3rem!important}.mr-xl-5,.mx-xl-5{margin-right:3rem!important}.mb-xl-5,.my-xl-5{margin-bottom:3rem!important}.ml-xl-5,.mx-xl-5{margin-left:3rem!important}.p-xl-0{padding:0!important}.pt-xl-0,.py-xl-0{padding-top:0!important}.pr-xl-0,.px-xl-0{padding-right:0!important}.pb-xl-0,.py-xl-0{padding-bottom:0!important}.pl-xl-0,.px-xl-0{padding-left:0!important}.p-xl-1{padding:.25rem!important}.pt-xl-1,.py-xl-1{padding-top:.25rem!important}.pr-xl-1,.px-xl-1{padding-right:.25rem!important}.pb-xl-1,.py-xl-1{padding-bottom:.25rem!important}.pl-xl-1,.px-xl-1{padding-left:.25rem!important}.p-xl-2{padding:.5rem!important}.pt-xl-2,.py-xl-2{padding-top:.5rem!important}.pr-xl-2,.px-xl-2{padding-right:.5rem!important}.pb-xl-2,.py-xl-2{padding-bottom:.5rem!important}.pl-xl-2,.px-xl-2{padding-left:.5rem!important}.p-xl-3{padding:1rem!important}.pt-xl-3,.py-xl-3{padding-top:1rem!important}.pr-xl-3,.px-xl-3{padding-right:1rem!important}.pb-xl-3,.py-xl-3{padding-bottom:1rem!important}.pl-xl-3,.px-xl-3{padding-left:1rem!important}.p-xl-4{padding:1.5rem!important}.pt-xl-4,.py-xl-4{padding-top:1.5rem!important}.pr-xl-4,.px-xl-4{padding-right:1.5rem!important}.pb-xl-4,.py-xl-4{padding-bottom:1.5rem!important}.pl-xl-4,.px-xl-4{padding-left:1.5rem!important}.p-xl-5{padding:3rem!important}.pt-xl-5,.py-xl-5{padding-top:3rem!important}.pr-xl-5,.px-xl-5{padding-right:3rem!important}.pb-xl-5,.py-xl-5{padding-bottom:3rem!important}.pl-xl-5,.px-xl-5{padding-left:3rem!important}.m-xl-auto{margin:auto!important}.mt-xl-auto,.my-xl-auto{margin-top:auto!important}.mr-xl-auto,.mx-xl-auto{margin-right:auto!important}.mb-xl-auto,.my-xl-auto{margin-bottom:auto!important}.ml-xl-auto,.mx-xl-auto{margin-left:auto!important}}.text-justify{text-align:justify!important}.text-nowrap{white-space:nowrap!important}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-left{text-align:left!important}.text-right{text-align:right!important}.text-center{text-align:center!important}@media (min-width:576px){.text-sm-left{text-align:left!important}.text-sm-right{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.text-md-left{text-align:left!important}.text-md-right{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.text-lg-left{text-align:left!important}.text-lg-right{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.text-xl-left{text-align:left!important}.text-xl-right{text-align:right!important}.text-xl-center{text-align:center!important}}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.font-weight-light{font-weight:300!important}.font-weight-normal{font-weight:400!important}.font-weight-bold{font-weight:700!important}.font-italic{font-style:italic!important}.text-white{color:#fff!important}.text-primary{color:#007bff!important}a.text-primary:focus,a.text-primary:hover{color:#0062cc!important}.text-secondary{color:#6c757d!important}a.text-secondary:focus,a.text-secondary:hover{color:#545b62!important}.text-success{color:#28a745!important}a.text-success:focus,a.text-success:hover{color:#1e7e34!important}.text-info{color:#17a2b8!important}a.text-info:focus,a.text-info:hover{color:#117a8b!important}.text-warning{color:#ffc107!important}a.text-warning:focus,a.text-warning:hover{color:#d39e00!important}.text-danger{color:#dc3545!important}a.text-danger:focus,a.text-danger:hover{color:#bd2130!important}.text-light{color:#f8f9fa!important}a.text-light:focus,a.text-light:hover{color:#dae0e5!important}.text-dark{color:#343a40!important}a.text-dark:focus,a.text-dark:hover{color:#1d2124!important}.text-muted{color:#6c757d!important}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.visible{visibility:visible!important}.invisible{visibility:hidden!important}@media print{*,::after,::before{text-shadow:none!important;box-shadow:none!important}a:not(.btn){text-decoration:underline}abbr[title]::after{content:" (" attr(title) ")"}pre{white-space:pre-wrap!important}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}@page{size:a3}body{min-width:992px!important}.container{min-width:992px!important}.navbar{display:none}.badge{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}} +/*# sourceMappingURL=bootstrap.min.css.map */ \ No newline at end of file diff --git a/pivot4j-analytics/src/main/webapp/resources/pivot4j/css/jquery.ui.tabs.css b/pivot4j-analytics/src/main/webapp/resources/pivot4j/css/jquery.ui.tabs.css index 26f9c27e..d8fbe689 100644 --- a/pivot4j-analytics/src/main/webapp/resources/pivot4j/css/jquery.ui.tabs.css +++ b/pivot4j-analytics/src/main/webapp/resources/pivot4j/css/jquery.ui.tabs.css @@ -1,52 +1,47 @@ -/*! - * jQuery UI Tabs 1.10.3 - * http://jqueryui.com - * - * Copyright 2013 jQuery Foundation and other contributors - * Released under the MIT license. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Tabs#theming - */ +/*! jQuery UI - v1.12.1 - 2019-02-24 +* http://jqueryui.com +* Includes: draggable.css, core.css, resizable.css, selectable.css, sortable.css, accordion.css, autocomplete.css, menu.css, button.css, controlgroup.css, checkboxradio.css, datepicker.css, dialog.css, progressbar.css, selectmenu.css, slider.css, spinner.css, tabs.css, tooltip.css, theme.css +* To view and modify this theme, visit http://jqueryui.com/themeroller/?scope=&folderName=base&cornerRadiusShadow=8px&offsetLeftShadow=0px&offsetTopShadow=0px&thicknessShadow=5px&opacityShadow=30&bgImgOpacityShadow=0&bgTextureShadow=flat&bgColorShadow=666666&opacityOverlay=30&bgImgOpacityOverlay=0&bgTextureOverlay=flat&bgColorOverlay=aaaaaa&iconColorError=cc0000&fcError=5f3f3f&borderColorError=f1a899&bgTextureError=flat&bgColorError=fddfdf&iconColorHighlight=777620&fcHighlight=777620&borderColorHighlight=dad55e&bgTextureHighlight=flat&bgColorHighlight=fffa90&iconColorActive=ffffff&fcActive=ffffff&borderColorActive=003eff&bgTextureActive=flat&bgColorActive=007fff&iconColorHover=555555&fcHover=2b2b2b&borderColorHover=cccccc&bgTextureHover=flat&bgColorHover=ededed&iconColorDefault=777777&fcDefault=454545&borderColorDefault=c5c5c5&bgTextureDefault=flat&bgColorDefault=f6f6f6&iconColorContent=444444&fcContent=333333&borderColorContent=dddddd&bgTextureContent=flat&bgColorContent=ffffff&iconColorHeader=444444&fcHeader=333333&borderColorHeader=dddddd&bgTextureHeader=flat&bgColorHeader=e9e9e9&cornerRadius=3px&fwDefault=normal&fsDefault=1em&ffDefault=Arial%2CHelvetica%2Csans-serif +* Copyright jQuery Foundation and other contributors; Licensed MIT */ + .ui-tabs { - position: relative;/* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ - padding: .2em; + position: relative;/* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ + padding: .2em; } .ui-tabs .ui-tabs-nav { - margin: 0; - padding: .2em .2em 0; + margin: 0; + padding: .2em .2em 0; } .ui-tabs .ui-tabs-nav li { - list-style: none; - float: left; - position: relative; - top: 0; - margin: 1px .2em 0 0; - border-bottom-width: 0; - padding: 0; - white-space: nowrap; -} -.ui-tabs .ui-tabs-nav li a { - float: left; - padding: .5em 1em; - text-decoration: none; + list-style: none; + float: left; + position: relative; + top: 0; + margin: 1px .2em 0 0; + border-bottom-width: 0; + padding: 0; + white-space: nowrap; +} +.ui-tabs .ui-tabs-nav .ui-tabs-anchor { + float: left; + padding: .5em 1em; + text-decoration: none; } .ui-tabs .ui-tabs-nav li.ui-tabs-active { - margin-bottom: -1px; - padding-bottom: 1px; + margin-bottom: -1px; + padding-bottom: 1px; } -.ui-tabs .ui-tabs-nav li.ui-tabs-active a, -.ui-tabs .ui-tabs-nav li.ui-state-disabled a, -.ui-tabs .ui-tabs-nav li.ui-tabs-loading a { - cursor: text; +.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor, +.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor, +.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor { + cursor: text; } -.ui-tabs .ui-tabs-nav li a, /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ -.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active a { - cursor: pointer; +.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor { + cursor: pointer; } .ui-tabs .ui-tabs-panel { - display: block; - border-width: 0; - padding: 1em 1.4em; - background: none; + display: block; + border-width: 0; + padding: 1em 1.4em; + background: none; } diff --git a/pivot4j-analytics/src/main/webapp/resources/pivot4j/css/signin.css b/pivot4j-analytics/src/main/webapp/resources/pivot4j/css/signin.css new file mode 100644 index 00000000..4ca877bb --- /dev/null +++ b/pivot4j-analytics/src/main/webapp/resources/pivot4j/css/signin.css @@ -0,0 +1,77 @@ +body { + background-image: url("../images/backLogon.png"); +} + +html { + margin: 0; + padding: 0; + height: 100%; + background: #C8C3C3 !important; +} +.user_card { + height: 400px; + width: 350px; + margin-top: auto; + margin-bottom: auto; + position: relative; + display: flex; + justify-content: center; + flex-direction: column; + padding: 10px; + box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); + border-radius: 5px; + +} +.brand_logo_container { + position: absolute; + height: 170px; + width: 170px; + top: -75px; + border-radius: 50%; + background: #C8C3C3; + padding: 10px; + text-align: center; +} +.brand_logo { + height: 150px; + width: 150px; + border-radius: 50%; + border: 2px solid white; +} +.form_container { + margin-top: 100px; +} +.login_btn { + width: 100%; + background: #4d4d4d !important; + color: white !important; + font-size: 15px !important +} +.login_btn:focus { + box-shadow: none !important; + outline: 0px !important; +} +.login_container { + padding: 0 2rem; +} +.input-group-text { + background: #4d4d4d !important; + color: white !important; + border: 0 !important; + border-radius: 0.25rem 0 0 0.25rem !important; +} +.input_user, +.input_pass:focus { + box-shadow: none !important; + outline: 0px !important; + font-size: 15px !important; +} +.custom-checkbox .custom-control-input:checked~.custom-control-label::before { + background-color: #4d4d4d !important; +} +a { + color: white; + text-decoration: none; + background-color: transparent; + -webkit-text-decoration-skip: objects; +} \ No newline at end of file diff --git a/pivot4j-analytics/src/main/webapp/resources/pivot4j/css/style.css b/pivot4j-analytics/src/main/webapp/resources/pivot4j/css/style.css index 8e6e85af..68c243e3 100644 --- a/pivot4j-analytics/src/main/webapp/resources/pivot4j/css/style.css +++ b/pivot4j-analytics/src/main/webapp/resources/pivot4j/css/style.css @@ -1,588 +1,595 @@ -body,td,th,.ui-widget { - font-size: 9pt; - font-family: Arial, Helvetica, sans-serif; +* { + -webkit-print-color-adjust: exact !important; /* Chrome, Safari */ + color-adjust: exact !important; /*Firefox*/ +} + +body { + font-size: 9pt; + font-family: Arial, Helvetica, sans-serif; } form { - margin: 0 0 0 0; - padding: 0 0 0 0; + margin: 0 0 0 0; + padding: 0 0 0 0; } .hide-on-embed { - display: none !important; + display: none !important; } .pe-layout-pane-header { - padding-left: 3px; + padding-left: 3px; } .blockOverlay { - z-index: 2000 !important; + z-index: 2000 !important; } .blockMsg { - z-index: 2100 !important; - top: 50% !important; - left: 50% !important; - margin-top: -35px !important; - margin-left: -107px !important; + z-index: 2100 !important; + top: 50% !important; + left: 50% !important; + margin-top: -35px !important; + margin-left: -107px !important; } .pe-blockui-content span { - white-space: nowrap; + white-space: nowrap; } .ui-force-hidden { - display: none !important; + display: none !important; } #main-content-pane { - padding: 0; - border: none; - overflow: hidden; + padding: 0; + border: none; + overflow: hidden; } #main-content-pane .ui-tabs-panel { - position: absolute; - top: 32px; - bottom: 0; - padding: 0; - left: 0; - right: 0; + position: absolute; + top: 32px; + bottom: 0; + padding: 0; + left: 0; + right: 0; } #tab-panel li.dirty a { - text-decoration: underline; - font-style: oblique; + text-decoration: underline; + font-style: oblique; } .node-active-file { - font-weight: bold; - font-style: oblique; + font-weight: bold; + font-style: oblique; } body.report .pe-layout-pane-header { - border-width: 1px; + border-width: 1px; } #navigator-pane .pe-layout-pane-content .pe-layout-pane-header { - border-width: 0; + border-width: 0; } #source-tree-pane .pe-layout-pane-header { - padding-left: 6px; + padding-left: 6px; } #target-tree-pane .pe-layout-pane-header { - padding-left: 6px; + padding-left: 6px; } #toolbar-pane { - border: none; - overflow: hidden; + border: none; + overflow: hidden; } .ui-toolbar-group-left,.ui-toolbar-group-right { - white-space: nowrap; + white-space: nowrap; } #toolbar-pane.pe-layout-pane-content { - padding: 0; - overflow: hidden; + padding: 0; + overflow: hidden; } #toolbar-pane .ui-selectonemenu { - vertical-align: middle; + vertical-align: middle; } #navigator-pane { - z-index: 10; + z-index: 10; } #navigator-pane .ui-tree { - border: none; - width: auto; + border: none; + width: auto; } #navigator-pane .ui-tree-container { - overflow: visible; - padding: 0; + overflow: hidden !important; + padding: 0; + } #navigator-pane .ui-layout-content { - padding-right: 0; + padding-right: 0; } .embeded #toolbar-form { - margin-bottom: 10px; + margin-bottom: 10px; } #toolbar-form .ui-icon-info { - background-image: url('#{resource['pivot4j:images/logo16.png']}'); - background-position: 0 center; - border-radius: 0 0 0 0; + background-image: url("#{resource['pivot4j:images/logo16.png']}"); + background-position: 0 center; + border-radius: 0 0 0 0; } .navigator .ui-treenode-icon.ui-icon { - border-radius: 0; + border-radius: 0; } .ui-treenode-icon.ui-icon-dim { - background-image: url('#{resource['pivot4j:images/dimension.gif']}'); - background-position: 0 0; + background-image: url("#{resource['pivot4j:images/dimension.gif']}"); + background-position: 0 0; } .ui-treenode-icon.ui-icon-hier { - background-image: url('#{resource['pivot4j:images/hierarchy.gif']}'); - background-position: 0 0; + background-image: url("#{resource['pivot4j:images/hierarchy.gif']}"); + background-position: 0 0; } .ui-treenode-icon.ui-icon-level0 { - background-image: url('#{resource['pivot4j:images/level_0.gif']}'); - background-position: 0 0; + background-image: url("#{resource['pivot4j:images/level_0.gif']}"); + background-position: 0 0; } .ui-treenode-icon.ui-icon-level1 { - background-image: url('#{resource['pivot4j:images/level_1.gif']}'); - background-position: 0 0; + background-image: url("#{resource['pivot4j:images/level_1.gif']}"); + background-position: 0 0; } .ui-treenode-icon.ui-icon-level2 { - background-image: url('#{resource['pivot4j:images/level_2.gif']}'); - background-position: 0 0; + background-image: url("#{resource['pivot4j:images/level_2.gif']}"); + background-position: 0 0; } .ui-treenode-icon.ui-icon-level3 { - background-image: url('#{resource['pivot4j:images/level_3.gif']}'); - background-position: 0 0; + background-image: url("#{resource['pivot4j:images/level_3.gif']}"); + background-position: 0 0; } .ui-treenode-icon.ui-icon-level4 { - background-image: url('#{resource['pivot4j:images/level_4.gif']}'); - background-position: 0 0; + background-image: url("#{resource['pivot4j:images/level_4.gif']}"); + background-position: 0 0; } .ui-treenode-icon.ui-icon-level5 { - background-image: url('#{resource['pivot4j:images/level_5.gif']}'); - background-position: 0 0; + background-image: url("#{resource['pivot4j:images/level_5.gif']}"); + background-position: 0 0; } .ui-treenode-icon.ui-icon-level6 { - background-image: url('#{resource['pivot4j:images/level_6.gif']}'); - background-position: 0 0; + background-image: url("#{resource['pivot4j:images/level_6.gif']}"); + background-position: 0 0; } .ui-treenode-icon.ui-icon-level7 { - background-image: url('#{resource['pivot4j:images/level_7.gif']}'); - background-position: 0 0; + background-image: url("#{resource['pivot4j:images/level_7.gif']}"); + background-position: 0 0; } .ui-treenode-icon.ui-icon-level8 { - background-image: url('#{resource['pivot4j:images/level_8.gif']}'); - background-position: 0 0; + background-image: url("#{resource['pivot4j:images/level_8.gif']}"); + background-position: 0 0; } .ui-treenode-icon.ui-icon-member { - background-image: url('#{resource['pivot4j:images/member.gif']}'); - background-position: 0 0; + background-image: url("#{resource['pivot4j:images/member.gif']}"); + background-position: 0 0; } .ui-treenode-icon.ui-icon-measure { - background-image: url('#{resource['pivot4j:images/measure.gif']}'); - background-position: 0 0; + background-image: url("#{resource['pivot4j:images/measure.gif']}"); + background-position: 0 0; } .ui-treenode-icon.ui-icon-cols,.ui-widget-header .ui-icon-cols { - background-image: url('#{resource['pivot4j:images/columns.gif']}'); - background-position: 0 0; + background-image: url("#{resource['pivot4j:images/columns.gif']}"); + background-position: 0 0; } .ui-treenode-icon.ui-icon-rows,.ui-widget-header .ui-icon-rows { - background-image: url('#{resource['pivot4j:images/rows.gif']}'); - background-position: 0 0; + background-image: url("#{resource['pivot4j:images/rows.gif']}"); + background-position: 0 0; } .ui-icon-none { - background-image: none !important; + background-image: none !important; } #source-tree-pane .ui-treenode .ui-state-highlight { - background: none !important; - text-shadow: none !important; - color: inherit !important; - text-decoration: underline; + background: none !important; + text-shadow: none !important; + color: inherit !important; + text-decoration: underline; } #cube-list-pane { - overflow: hidden; - white-space: nowrap; + overflow: hidden; + white-space: nowrap; + min-width: 100px !important; } #cube-list-pane label.cube-list-label { - margin-left: 5px; - margin-right: 5px; - float: left; - line-height: 22px; - vertical-align: middle; + margin-left: 5px; + margin-right: 5px; + float: left; + line-height: 22px; + vertical-align: middle; } .ui-draggable-dragging.node-hierarchy { - background-image: url('#{resource['pivot4j:images/hierarchy.gif']}'); - background-repeat: no-repeat; - background-position: left; - padding-left: 18px; + background-image: url("#{resource['pivot4j:images/hierarchy.gif']}"); + background-repeat: no-repeat; + background-position: left; + padding-left: 18px; } .ui-draggable-dragging.node-level { - background-repeat: no-repeat; - background-position: left; - padding-left: 18px; + background-repeat: no-repeat; + background-position: left; + padding-left: 18px; } .ui-draggable-dragging.node-member { - background-image: url('#{resource['pivot4j:images/measure.gif']}'); - background-repeat: no-repeat; - background-position: left; - padding-left: 18px; + background-image: url("#{resource['pivot4j:images/measure.gif']}"); + background-repeat: no-repeat; + background-position: left; + padding-left: 18px; } #grid-header-pane { - padding: 2px; - overflow: hidden; + padding: 2px; + overflow: hidden; } #content-pane .ui-layout-content { - padding: 6px 6px 0 0; + padding: 6px 6px 0 0; } #grid-content-pane { - padding: 0; - border: none; + padding: 0; + border: none; } .pivot-grid .value-cell, .pivot-grid .value-cell .ui-inputfield { - text-align: right; + text-align: right; } .pivot-grid .value-cell .ui-button { - float: right; + float: right; } .value-cell.cell-odd { - background-color: rgb(242, 245, 249); - color: rgb(48, 48, 48); + background-color: rgb(242, 245, 249); + color: rgb(48, 48, 48); } .pivot-grid .col-hdr-cell,.pivot-grid .agg-hdr { - white-space: nowrap; + white-space: nowrap; } .pivot-grid .row-hdr-cell,.filter-grid .row-hdr-cell { - vertical-align: top; - white-space: nowrap; - background-image: none; + vertical-align: top; + white-space: nowrap; + background-image: none; } .pivot-grid .col-agg-cell,.pivot-grid .row-agg-cell { - background-image: none; + background-image: none; } .pivot-grid .agg-title { - white-space: nowrap; + white-space: nowrap; } .pivot-grid .agg-cell,.pivot-grid .agg-title { - text-align: right; + text-align: right; } .pivot-grid .ui-panelgrid-header .agg-title { - text-align: center; + text-align: center; } .pivot-grid { - margin-bottom: 10px; + margin-bottom: 10px; } .filter-grid { - margin-right: 0.5em; - margin-top: 0.5em; - float: left; + margin-right: 0.5em; + margin-top: 0.5em; + float: left; } button.ui-button-icon-only { - width: 16px; - height: 16px; - margin-left: 3px; - margin-right: 3px; - vertical-align: middle; + width: 16px; + height: 16px; + margin-left: 3px; + margin-right: 3px; + vertical-align: middle !important; } span.ui-button-icon-only { - width: 16px; - height: 16px; + width: 16px; + height: 16px; } .filter-info .title { - clear: both; + clear: both; } .filter-panel { - width: 100%; + width: 100%; } .filter-panel td { - white-space: nowrap; - padding: 2px; + white-space: nowrap; + padding: 2px; } .filter-panel .ui-widget-header { - width: 80px; - padding: 0 5px 0 5px; - text-align: right; + width: 80px; + padding: 0 5px 0 5px; + text-align: right; } .filter-panel td.filter-items { - border: 1px dotted #a8a8a8; - width: 100%; + border: 1px dotted #a8a8a8; + width: 100%; } .filter-panel td.filter-items .ui-droppable { - height: 22px; + height: 22px; } .filter-panel td.filter-items .filter-items-hover { - border: 1px solid red; + border: 1px solid red; } .filter-panel .filter-item { - border-radius: 5px; - background-image: none; - margin-right: 2px; - padding: 0 5px 2px; - white-space: nowrap; - width: auto; - float: left; + border-radius: 5px; + background-image: none; + margin-right: 2px; + padding: 0 5px 2px; + white-space: nowrap; + width: auto; + float: left; } .filter-panel .filter-item a { - text-decoration: none; + text-decoration: none; } .filter-panel .filter-item .ui-button { - width: 16px; - height: 16px; - vertical-align: middle; + width: 16px; + height: 16px; + vertical-align: middle; } .filter-dialog .ui-tree { - margin-top: 0.4em; + margin-top: 0.4em; + overflow: auto !important; } .filter-dialog .ui-tree-container { - height: 240px !important; + height: 240px !important; } .filter-dialog .ui-dialog-buttonpane { - padding: 0.3em 0 0 0 !important; + padding: 0.3em 0 0 0 !important; } #mdx-editor-pane { - padding-bottom: 6px; + padding-bottom: 6px; } #mdx-editor-pane .pe-layout-pane-content { - padding: 0; + padding: 0; } #mdx-editor-pane .CodeMirror-scroll { - overflow-y: visible; - height: auto; + overflow-y: visible; + height: auto; } #mdx-editor-pane .query-info { - padding: 8px 5px 0px 5px; + padding: 8px 5px 0px 5px; } #mdx-editor-pane .ui-layout-north { - overflow: hidden; + overflow: hidden; } #mdx-editor-pane .ui-toolbar { - border: none; + border: none; } .ui-icon-title { - float: left; - margin-right: 2px; - border-radius: 0; + float: left; + margin-right: 2px; + border-radius: 0; } #content-pane .info-panel { - padding: 10px; - font-weight: bold; + padding: 10px; + font-weight: bold; } .ui-draggable { - cursor: pointer; + cursor: pointer; } .ui-draggable-dragging { - z-index: 10; + z-index: 10; } .ui-hide-display { - display: none !important; + display: none !important; } .about .about-title { - font-weight: bold; - font-size: large; + font-weight: bold; + font-size: large; } .about img { - float: left; - margin: 5px 15px 5px 5px; + float: left; + margin: 5px 15px 5px 5px; } .about .about-text { - display: block; - padding: 10px; + display: block; + padding: 10px; } .hierarchy-config .ui-dialog-content { - overflow: hidden; + overflow: hidden; } .hierarchy-config .member-panel .ui-panel-content { - padding: 5px 0 5px 0; - height: 340px; + padding: 5px 0 5px 0; + height: 340px; } .hierarchy-config .ui-tree-container { - padding: 0 0 0 0; + padding: 0 0 0 0; } .hierarchy-config .ui-tree { - height: 100%; - overflow: auto; + height: 100%; + overflow: auto; } .hierarchy-config .control-panel { - width: 102px; + width: 102px; } .hierarchy-config .ui-button { - width: 92px; - margin: 5px; + margin: 5px; } .hierarchy-config .source-panel .node-member { - + } .hierarchy-config .source-panel .node-member.selected { - color: #d0d0d0; + color: #d0d0d0; } .hierarchy-config .target-panel .node-member { - color: #d0d0d0; + color: #d0d0d0; } .hierarchy-config .target-panel .node-member.selected { - color: #000000; + color: #000000; } .hierarchy-contextmenu { - width: 180px; + width: 180px; } .aggregation-config .ui-picklist-list { - width: 120px !important; - height: 160px !important; + width: 120px !important; + height: 160px !important; } .aggregation-config .ui-panel { - float: left; - width: 320px; + float: left; + width: 380px; } .aggregation-config .ui-tabs .ui-tabs-panel { - height: 235px; + height: 235px; } .aggregation-config .rows-panel { - margin-right: 10px; + margin-right: 10px; } .chart-config .ui-tabs .ui-tabs-panel { - height: 235px; + height: 235px; } .properties-config .ui-dialog-content { - padding: 5px; + padding: 5px; } .properties-config .ui-layout-unit .ui-layout-unit-content { - padding: 0; + padding: 0; } .properties-config .ui-panelmenu .ui-panelmenu-content { - border: 0 none; + border: 0 none; } .properties-config .ui-breadcrumb ul li span { - float: left; + float: left; } .properties-config .info-panel { - margin-top: 5px; - margin-bottom: 5px; + margin-top: 5px; + margin-bottom: 5px; } .properties-config .ui-panelmenu .ui-panelmenu-header a { - padding-top: 5px; - padding-bottom: 5px; - font-size: 0.9em; + padding-top: 5px; + padding-bottom: 5px; + font-size: 0.9em; } .properties-config .editor-panel { - margin: 5px; + margin: 5px; } .properties-config .editor-panel .CodeMirror { - width: 340px; - height: 200px; + width: 340px; + height: 200px; } .drillthrough .ui-tree { - width: auto; - border: none; + width: auto; + border: none; } .drillthrough .ui-tree-container { - overflow: visible !important; + overflow: visible !important; } .drillthrough .field-set { - float: left; - margin: 0.5em; + float: left; + margin: 0.5em; } .ui-paginator .ui-paginator-rpp-options { - margin-left: 0.5em !important; + margin-left: 0.5em !important; } .ui-paginator .ui-paginator-jtp-select { - margin-left: 0.5em !important; - margin-right: 1.0em !important; + margin-left: 0.5em !important; + margin-right: 1.0em !important; } .CodeMirror-completions { - z-index: 2000 !important; + z-index: 2000 !important; } .CodeMirror-completions select { - color: #000000; + color: #000000; } .usage-info li { @@ -590,139 +597,569 @@ span.ui-button-icon-only { } .ui-dialog .ui-dialog-footer { - padding: 0; + padding: 0; } .ui-dialog .ui-dialog-buttonpane { - text-align: right !important; - margin: 0 !important; + text-align: right !important; + margin: 0 !important; } .ui-dialog .ui-dialog-buttonpane .ui-button { - margin: 5px 0 5px 5px !important; + margin: 5px 0 5px 5px !important; } .ui-dialog .info-panel { - text-align: left; - font-weight: normal; - padding: 5px; + text-align: left; + font-weight: normal; + padding: 5px; } .ui-dialog .ui-dialog-buttonpane .ui-messages { - text-align: left; + text-align: left; } .ui-dialog .ui-dialog-buttonpane .ui-messages div { - margin: 5px 0 5px 0 !important; + margin: 5px 0 5px 0 !important; } .ui-dialog .ui-dialog-content { - cursor: default; + cursor: default; + padding: 0 !important; } .ui-dialog-content .ui-layout-container { - width: 100% !important; - height: 100% !important; + width: 100% !important; + height: 100% !important; } .ui-confirm-dialog .ui-outputlabel { - margin-right: 5px; + margin-right: 5px; } .filter-dialog .ui-tree-container { - margin: 5px 0; - height: 280px; + margin: 5px 0; + height: 280px; } label.ui-icon-cols,label.ui-icon-rows { - display: block; - height: 16px; - padding-left: 20px; - background-repeat: no-repeat; + display: block; + height: 16px; + padding-left: 20px; + background-repeat: no-repeat; } label.ui-icon-cols { - background-image: url('#{resource['pivot4j:images/columns.gif']}'); + background-image: url("#{resource['pivot4j:images/columns.gif']}"); } label.ui-icon-rows { - background-image: url('#{resource['pivot4j:images/rows.gif']}'); + background-image: url("#{resource['pivot4j:images/rows.gif']}"); } td.field-name,th.field-name { - padding-right: 10px; - text-align: right; + padding-right: 10px; + text-align: right; } span.unit { - margin-left: 5px; + margin-left: 5px; } .ui-menu { - width: 180px !important; + width: 180px !important; + padding: 0.0em !important } .export-menu { - margin-right: 1px; + margin-right: 1px; } -#toolbar-form\3A charts_menu .ui-menuitem-text { - display: block; - width: 140px; -} +/*#toolbar-form\3A charts_menu .ui-menuitem-text { + display: block; + width: 140px; +}*/ @media print { - .ui-button { - display: none !important; - } + .ui-button { + display: none !important; + } } div.ui-tabs-panel iframe { - width: 100%; - height: 100%; - border: none; + width: 100%; + height: 100%; + border: none; } body.ie-compat div.ui-tabs-panel iframe { - height: expression(this.parentNode.offsetHeight); + height: expression(this.parentNode.offsetHeight); } body.ie-compat .ui-toolbar .ui-button { - float: left; + float: left; } body.ie-compat .ui-toolbar .ui-selectonebutton { - float: left; + float: left; } body.ie-compat .ui-toolbar .ui-separator { - float: left; + float: left; } .migration-dialog .ui-tree { - border: none; - padding: 0; - margin: 0; - width: auto; + border: none; + padding: 0; + margin: 0; + width: auto; } .migration-dialog .ui-layout-container { - width: 100%; - height: 300px !important; + width: 100%; + height: 300px !important; } .migration-dialog .ui-layout-resizer { - display: none !important; + display: none !important; } .migration-dialog .ui-layout-pane-center { - width: auto !important; + width: auto !important; } .migration-dialog .ui-layout-container .ui-layout-pane-north { - border: none; + border: none; } .wrap { - white-space: normal !important; + white-space: normal !important; +} + +.ui-button { + padding: 4px 10px !important; +} + +/*div.ui-button { + overflow: -webkit-paged-y !important; + padding: 2.8px 10px !important; +}*/ + +.ui-menubutton { + padding: 0; + position: relative !important; + display: inline !important; +} + +div.ui-chkbox span.ui-icon-check { + border: 1px solid #3c8dbc !important; + background: #3c8dbc !important; +} + +div.ui-chkbox-box.ui-state-default span.ui-chkbox-icon:before { + color: #fff !important; +} + +/*div.ui-button { + overflow: middle !important; +}*/ + +.pe-layout-pane-content { + padding: 1px !important; + overflow: auto; +} + +.ui-toolbar { + padding: .1em !important; +} + +.ui-datatable .ui-datatable-header { + text-align: right !important; +} + +.ui-datatable thead th, .ui-datatable tbody td, .ui-datatable tfoot td{ + padding: 1px 10px!important; + overflow: hidden; + border-width: 1px; + border-style: solid; +} + +.ui-datatable table{ + border-collapse: collapse; + width: 100%; + table-layout: auto!important; +} + +.ui-datatable tr.ui-datatable-even:hover, .ui-datatable tr.ui-datatable-odd:hover{ + background: #78BCFF; +} + +.ui-button-icon-only .ui-button-text { + padding: .0 !important; + text-indent: -9999999px; +} + +div.ui-selectonemenu, div.ui-fluid div.ui-selectonemenu, div.ui-selectcheckboxmenu, div.ui-fluid div.ui-selectcheckboxmenu { + height: 29px; + display: inline-grid !important; + overflow: hidden; + border-color: #d2d6de; + border-bottom-left-radius: 3px; + border-top-left-radius: 3px; + -moz-border-radius-bottomleft: 3px; + -moz-border-radius-topleft: 3px; + -webkit-border-top-left-radius: 3px; + -webkit-border-bottom-left-radius: 3px; + min-width: 210px !important; +} + +.ui-selectonemenu { + display: inline-block; + position: relative; + width: auto; + zoom: 1; + cursor: pointer; + padding-right: 0em !important; +} + +.ui-selectonemenu .ui-selectonemenu-trigger .ui-icon { + position: initial !important; +} + +/*.ui-button-icon-only .ui-icon { + left: 50% !important; + margin-left: -8px !important; + margin-top: -6px !important; + top: auto !important; +}*/ + +button.ui-button { + vertical-align: top !important; +} + +body .ui-picklist div.ui-picklist-buttons-cell button, body .ui-picklist.ui-picklist-responsive div.ui-picklist-buttons-cell button { + background-color: transparent; + border: none; + width: 32px; + height: 32px; +} +li.header { + text-transform: uppercase; +} + +.sidebar-form { + border-radius: 3px; + border: 1px solid #374850; + margin: 10px 10px; +} +.sidebar-form, .sidebar-menu>li.header { + overflow: hidden; + text-overflow: clip; +} + +button.ui-button{ + vertical-align: top !important; +} + +div.ui-selectbooleanbutton { + overflow: initial !important; +} + +button.ui-button-text-icon-left .ui-button-text, .ui-button-text-icon-right .ui-button-text { + padding: .3em 1em .3em 2.1em !important; +} + +code[class*="language-"], +pre[class*="language-"] { + color: black; + background: none; + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + + -webkit-hyphens: none; + -moz-hyphens: none; + -ms-hyphens: none; + hyphens: none; +} + +/* Code blocks */ +pre[class*="language-"] { + position: relative; + margin: .5em 0; + box-shadow: -1px 0px 0px 0px #358ccb, 0px 0px 0px 1px #dfdfdf; + border-left: 10px solid #358ccb; + background-color: #fdfdfd; + background-image: linear-gradient(transparent 50%, rgba(69, 142, 209, 0.04) 50%); + background-size: 3em 3em; + background-origin: content-box; + overflow: visible; + padding: 0; +} + +code[class*="language"] { + max-height: inherit; + height: 100%; + padding: 0 1em; + display: block; + overflow: auto; +} + +/* Margin bottom to accomodate shadow */ +:not(pre) > code[class*="language-"], +pre[class*="language-"] { + background-color: #fdfdfd; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + margin-bottom: 1em; +} + +/* Inline code */ +:not(pre) > code[class*="language-"] { + position: relative; + padding: .2em; + border-radius: 0.3em; + color: #c92c2c; + border: 1px solid rgba(0, 0, 0, 0.1); + display: inline; + white-space: normal; +} + +pre[class*="language-"]:before, +pre[class*="language-"]:after { + content: ''; + z-index: -2; + display: block; + position: absolute; + bottom: 0.75em; + left: 0.18em; + width: 40%; + height: 20%; + max-height: 13em; + box-shadow: 0px 13px 8px #979797; + -webkit-transform: rotate(-2deg); + -moz-transform: rotate(-2deg); + -ms-transform: rotate(-2deg); + -o-transform: rotate(-2deg); + transform: rotate(-2deg); +} + +:not(pre) > code[class*="language-"]:after, +pre[class*="language-"]:after { + right: 0.75em; + left: auto; + -webkit-transform: rotate(2deg); + -moz-transform: rotate(2deg); + -ms-transform: rotate(2deg); + -o-transform: rotate(2deg); + transform: rotate(2deg); +} + +.token.comment, +.token.block-comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: #7D8B99; +} + +.token.punctuation { + color: #5F6364; +} + +.token.property, +.token.tag, +.token.boolean, +.token.number, +.token.function-name, +.token.constant, +.token.symbol, +.token.deleted { + color: #c92c2c; +} + +.token.selector, +.token.attr-name, +.token.string, +.token.char, +.token.function, +.token.builtin, +.token.inserted { + color: #2f9c0a; +} + +.token.operator, +.token.entity, +.token.url, +.token.variable { + color: #a67f59; + background: rgba(255, 255, 255, 0.5); +} + +.token.atrule, +.token.attr-value, +.token.keyword, +.token.class-name { + color: #1990b8; +} + +.token.regex, +.token.important { + color: #e90; +} + +.language-css .token.string, +.style .token.string { + color: #a67f59; + background: rgba(255, 255, 255, 0.5); +} + +.token.important { + font-weight: normal; +} + +.token.bold { + font-weight: bold; +} +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} + +.namespace { + opacity: .7; +} + +@media screen and (max-width: 767px) { + pre[class*="language-"]:before, + pre[class*="language-"]:after { + bottom: 14px; + box-shadow: none; + } + +} +/* Plugin styles */ +.token.tab:not(:empty):before, +.token.cr:before, +.token.lf:before { + color: #e0d7d1; +} +/* Plugin styles: Line Numbers */ +pre[class*="language-"].line-numbers { + padding-left: 0; +} + +pre[class*="language-"].line-numbers code { + padding-left: 3.8em; +} + +pre[class*="language-"].line-numbers .line-numbers-rows { + left: 0; +} +/* Plugin styles: Line Highlight */ +pre[class*="language-"][data-line] { + padding-top: 0; + padding-bottom: 0; + padding-left: 0; +} + +pre[data-line] code { + position: relative; + padding-left: 4em; +} + +pre .line-highlight { + margin-top: 0; +} + +.month-picker{display:inline-block;position:absolute;z-index:9999}.month-picker table{border-collapse:separate;border-spacing:2px 2px}.month-picker td{padding:0}.month-picker .ui-button-text{padding:.4em 0}.month-picker-header{margin:3px 3px 0}.month-picker-year-table{width:100%;-ms-user-select:none;-moz-user-select:-moz-none;-khtml-user-select:none;-webkit-user-select:none;user-select:none}.month-picker-year-table a{border:1px solid transparent}.month-picker-year-table .ui-button{font-size:1.1em;width:1.5em;height:1.5em;cursor:default;margin:0}.month-picker-year-table .month-picker-title{text-align:center}.month-picker-year-table .month-picker-title .ui-button{font-size:1em;padding:.1em 0;width:100%;font-weight:700}.month-picker-year-table .ui-button-text{padding:0}.month-picker-month-table td{height:35px;text-align:center}.month-picker-month-table .ui-button{width:4.2em;margin:.2em}.month-picker-open-button{height:20px;width:20px;vertical-align:bottom}.month-picker-invalid-message{display:none;background-color:#ff0}.month-picker-disabled{background-color:#e1e1e1} + +.ui-tree { + width: auto !important; + position: relative; +} + +.ui-tree .ui-tree-container { + margin: 0; + padding: 3px; + white-space: nowrap; + overflow: visible !important; +} + +body li.ui-menuitem span.ui-menuitem-text { + padding-left: 1px !important; +} + +body .ui-picklist div.ui-picklist-buttons-cell button, body .ui-picklist.ui-picklist-responsive div.ui-picklist-buttons-cell button { + background-color: #666 !important; +} + +li.ui-menuitem>a.ui-menuitem-link { + margin-left: 1px !important; +} + +.ui-menu .ui-menuitem-link { + width: 100% !important; +} + +body .ui-picklist button.ui-picklist-button-remove, body .ui-picklist.ui-picklist-responsive button.ui-picklist-button-remove { + transform: rotate(180deg) !important; +} + +div.ui-picklist-buttons-cell button > span::before { + position: initial !important; +} + +span.ui-icon-minus { + position: relative !important; + margin-left: -9px !important; +} + +span.ui-icon-plus { + position: relative !important; + margin-left: -9px !important; + +} + +span.ui-icon-minusthick:before, span.ui-icon-minus:before { + font-size: 10.0px !important; + padding: 0 7px !impotant; +} + +span.ui-icon-plusthick:before, span.ui-icon-plus:before { + font-size: 10.0px !important; + padding: 0 7px !impotant; +} + +.member-panel{ + width: 40% !important; +} + +.ui-toolbar-group-left { + float: left; + overflow: auto !important; + width: 100%; + display: contents; +} + +.ui-spinner-button { + height: 61% !important; + width: 100% !important; + right: -36px !important; +} + +.theme-switcher { + vertical-align: top !important; } \ No newline at end of file diff --git a/pivot4j-analytics/src/main/webapp/resources/pivot4j/images/backLogon.png b/pivot4j-analytics/src/main/webapp/resources/pivot4j/images/backLogon.png new file mode 100644 index 00000000..df333042 Binary files /dev/null and b/pivot4j-analytics/src/main/webapp/resources/pivot4j/images/backLogon.png differ diff --git a/pivot4j-analytics/src/main/webapp/resources/pivot4j/images/logoLogin.png b/pivot4j-analytics/src/main/webapp/resources/pivot4j/images/logoLogin.png new file mode 100644 index 00000000..04e11e46 Binary files /dev/null and b/pivot4j-analytics/src/main/webapp/resources/pivot4j/images/logoLogin.png differ diff --git a/pivot4j-analytics/src/main/webapp/resources/pivot4j/images/logout.png b/pivot4j-analytics/src/main/webapp/resources/pivot4j/images/logout.png new file mode 100644 index 00000000..58b266dd Binary files /dev/null and b/pivot4j-analytics/src/main/webapp/resources/pivot4j/images/logout.png differ diff --git a/pivot4j-analytics/src/main/webapp/resources/pivot4j/js/codemirror-mode.js b/pivot4j-analytics/src/main/webapp/resources/pivot4j/js/codemirror-mode.js index 68a6e5fc..21eb2269 100644 --- a/pivot4j-analytics/src/main/webapp/resources/pivot4j/js/codemirror-mode.js +++ b/pivot4j-analytics/src/main/webapp/resources/pivot4j/js/codemirror-mode.js @@ -1,602 +1,602 @@ -CodeMirror - .defineMode( - "mdx", - function(config, parserConfig) { - var keywords = parserConfig.keywords, functions = parserConfig.functions, properties = parserConfig.properties, multiLineStrings = parserConfig.multiLineStrings; - var isOperatorChar = /[+\-*&%=<>!?:\/|]/; - function chain(stream, state, f) { - state.tokenize = f; - return f(stream, state); - } - - function ret(tp, style) { - type = tp; - return style; - } - - function tokenBase(stream, state) { - var ch = stream.next(); - // start of string? - if (ch == '"' || ch == "'") - return chain(stream, state, tokenString(ch)); - // is it one of the special signs {}().,;? Seperator? - else if (/[{}\(\),;\.]/.test(ch)) - return ret("bracket", "bracket"); - // start of a number value? - else if (/\d/.test(ch)) { - stream.eatWhile(/[\w\.]/); - return ret("number", "number"); - } - // multi line comment or simple operator? - else if (ch == "/") { - if (stream.eat("*")) { - return chain(stream, state, tokenComment); - } else { - stream.eatWhile(isOperatorChar); - return ret("operator", "operator"); - } - } - // single line comment or simple operator? - else if (ch == "-") { - if (stream.eat("-")) { - stream.skipToEnd(); - return ret("comment", "comment"); - } else { - stream.eatWhile(isOperatorChar); - return ret("operator", "operator"); - } - } - // is it an identifier? - else if (ch == "[") { - return chain(stream, state, tokenString("]")); - } - // is it a operator? - else if (isOperatorChar.test(ch)) { - stream.eatWhile(isOperatorChar); - return ret("operator", "operator"); - } else { - // get the whole word - stream.eatWhile(/[\w\$_]/); - // is it one of the listed keywords? - if (keywords - && keywords.propertyIsEnumerable(stream - .current().toLowerCase())) - return ret("keyword", "keyword"); - // is it one of the listed functions? - if (functions - && functions.propertyIsEnumerable(stream - .current().toLowerCase())) - return ret("keyword", "builtin"); - // is it one of the listed types? - if (properties - && properties.propertyIsEnumerable(stream - .current().toLowerCase())) - return ret("keyword", "variable-2"); - // default: just a "variable" - return ret("word", "variable"); - } - } - - function tokenString(quote) { - return function(stream, state) { - var escaped = false, next, end = false; - while ((next = stream.next()) != null) { - if (next == quote && !escaped) { - end = true; - break; - } - escaped = !escaped && next == "\\"; - } - if (end || !(escaped || multiLineStrings)) - state.tokenize = tokenBase; - return ret("string", "qualifier"); - }; - } - - function tokenComment(stream, state) { - var maybeEnd = false, ch; - while (ch = stream.next()) { - if (ch == "/" && maybeEnd) { - state.tokenize = tokenBase; - break; - } - maybeEnd = (ch == "*"); - } - return ret("comment", "comment"); - } - - // Interface - return { - startState : function(basecolumn) { - return { - tokenize : tokenBase, - startOfLine : true - }; - }, - - token : function(stream, state) { - if (stream.eatSpace()) - return null; - var style = state.tokenize(stream, state); - return style; - } - }; - }); - -(function() { - function keywords(str) { - var obj = {}, words = str.split(" "); - for ( var i = 0; i < words.length; ++i) - obj[words[i]] = true; - return obj; - } - - var mdxKeywords = "select from on columns rows where with not in properties"; - - var mdxFunctions = "hierarchize crossjoin union filter iif format exists except " - + "dateDiff dateAdd bottomCount bottomSum"; - - var mdxProperties = "null children descendants members firstChild firstSibling lastChild " - + "lastSibling parent name uniqueName nextMember hierarchy dimension currentMember " - + "defaultMember allMembers"; - - CodeMirror.defineMIME("text/x-mdx", { - name : "mdx", - keywords : keywords(mdxKeywords), - functions : keywords(mdxFunctions), - properties : keywords(mdxProperties) - }); -}()); - -CodeMirror - .defineMode( - "freemarker", - function(config, parserConfig) { - var keywords = parserConfig.keywords, functions = parserConfig.functions, properties = parserConfig.properties, multiLineStrings = parserConfig.multiLineStrings; - var isOperatorChar = /[+\-*&%=<>!?:\/|]/; - function chain(stream, state, f) { - state.tokenize = f; - return f(stream, state); - } - - function ret(tp, style) { - type = tp; - return style; - } - - function tokenBase(stream, state) { - var ch = stream.next(); - // start of string? - if (ch == '"' || ch == "'") - return chain(stream, state, tokenString(ch)); - // is it one of the special signs {}().,;? Seperator? - else if (/[<>\[\]{}\(\),;\.]/.test(ch)) - return ret("bracket", "bracket"); - // start of a number value? - else if (/\d/.test(ch)) { - stream.eatWhile(/[\w\.]/); - return ret("number", "number"); - } - // is it a operator? - else if (isOperatorChar.test(ch)) { - stream.eatWhile(isOperatorChar); - return ret("operator", "operator"); - } else { - // get the whole word - stream.eatWhile(/[\w\$_]/); - // is it one of the listed keywords? - if (keywords - && keywords.propertyIsEnumerable(stream - .current().toLowerCase())) - return ret("keyword", "keyword"); - // is it one of the listed functions? - if (functions - && functions.propertyIsEnumerable(stream - .current().toLowerCase())) - return ret("keyword", "builtin"); - // is it one of the listed types? - if (properties - && properties.propertyIsEnumerable(stream - .current().toLowerCase())) - return ret("keyword", "variable-2"); - // default: just a "variable" - return ret("word", "variable"); - } - } - - function tokenString(quote) { - return function(stream, state) { - var escaped = false, next, end = false; - while ((next = stream.next()) != null) { - if (next == quote && !escaped) { - end = true; - break; - } - escaped = !escaped && next == "\\"; - } - if (end || !(escaped || multiLineStrings)) - state.tokenize = tokenBase; - return ret("string", "qualifier"); - }; - } - - // Interface - return { - startState : function(basecolumn) { - return { - tokenize : tokenBase, - startOfLine : true - }; - }, - - token : function(stream, state) { - if (stream.eatSpace()) - return null; - var style = state.tokenize(stream, state); - return style; - } - }; - }); - -(function() { - function keywords(str) { - var obj = {}, words = str.split(" "); - for ( var i = 0; i < words.length; ++i) - obj[words[i]] = true; - return obj; - } - - var mdxKeywords = "#if #list #assign #else as"; - - var mdxFunctions = "html cap_first lower_case upper_case trim size int repeat"; - - var mdxProperties = "member level hierarchy model cube catalog locale dimension position " - + "columnPosition rowPosition cell cellType property roleName memberUtils attributes " - + "axis rowIndex rowIndex rowSpan columnSpan rowCount columnCount rowHeaderCount columnHeaderCount"; - - CodeMirror.defineMIME("text/x-freemarker", { - name : "freemarker", - keywords : keywords(mdxKeywords), - functions : keywords(mdxFunctions), - properties : keywords(mdxProperties) - }); -}()); - -(function() { - CodeMirror.pivot4jHint = function(editor, options) { - var keywords = []; - - return scriptHint(editor, keywords, function(e, cur) { - return e.getTokenAt(cur); - }, options); - }; - - function Pos(line, ch) { - if (!(this instanceof Pos)) - return new Pos(line, ch); - this.line = line; - this.ch = ch; - } - - function forEach(arr, f) { - for ( var i = 0, e = arr.length; i < e; ++i) { - f(arr[i]); - } - } - - function arrayContains(arr, item) { - if (!Array.prototype.indexOf) { - var i = arr.length; - while (i--) { - if (arr[i] === item) { - return true; - } - } - return false; - } - return arr.indexOf(item) != -1; - } - - function scriptHint(editor, keywords, getToken, options) { - var result = []; - - // Find the token at the cursor - var cur = editor.getCursor(); - var token = getToken(editor, cur); - - token.state = CodeMirror.innerMode(editor.getMode(), token.state).state; - - var ch = token.string.charAt(0); - - if (ch == "<" || ch == "/") { - if (ch == "<") { - result = [ "<#if ", "<#list ", "<#assign ", "<#else>" ]; - } else if (getToken(editor, Pos(cur.line, token.start)).string - .charAt(0) == "<") { - result = [ "/#if>", "/#list>", "/#assign>" ]; - } - } else { - var tprop = token; - - // If it's not a 'word-style' token, ignore the token. - if (!/^[\w$_]*$/.test(token.string)) { - token = tprop = { - start : cur.ch, - end : cur.ch, - string : "", - state : token.state, - type : token.string == "." ? "property" : null - }; - } - - var context = []; - - while (tprop) { - tprop = getToken(editor, Pos(cur.line, tprop.start)); - - if (tprop.string != ".") { - break; - } - - tprop = getToken(editor, Pos(cur.line, tprop.start)); - - context.push(tprop); - } - - result = getCompletions(token, context, keywords, options); - } - - return { - list : result, - from : Pos(cur.line, token.start), - to : Pos(cur.line, token.end) - }; - } - - var MetadataElement = { - name : "", - uniqueName : "", - caption : "", - description : "", - visible : true - }; - - var Database = { - name : "", - description : "", - catalogs : [], - dataSourceInfo : "", - olapConnection : {}, - providerName : "", - URL : "" - }; - - var Catalog = { - name : "", - schemas : [], - database : Database - }; - - var Schema = { - name : "", - catalog : Catalog, - cubes : [], - sharedDimensions : [], - supportedLocales : [] - }; - - var Cube = $.extend({ - hierarchies : [], - dimensions : [], - sets : [], - measures : [], - supportedLocales : [], - schema : Schema - }, MetadataElement); - - var Locale = { - language : "", - country : "", - variant : "" - }; - - var Model = { - cube : Cube, - roleName : "", - locale : Locale, - cellSet : {} - }; - - var Axis = { - axisOrdinal : 0 - }; - - var Position = { - ordinal : 0, - members : [] - }; - - var Dimension = $.extend({ - dimensionType : { - UNKNOWN : "", - TIME : "", - MEASURE : "", - OTHER : "", - QUANTITATIVE : "", - ACCOUNTS : "", - CUSTOMERS : "", - PRODUCTS : "", - SCENARIO : "", - UTILITY : "", - CURRENCY : "", - RATES : "", - CHANNEL : "", - PROMOTION : "", - ORGANIZATION : "", - BILL_OF_MATERIALS : "", - GEOGRAPHY : "" - }, - hierarchies : [] - }, MetadataElement); - - var Hierarchy = $.extend({ - dimension : Dimension, - levels : [], - rootMembers : [] - }, MetadataElement); - - Dimension.defaultHierarchy = Hierarchy; - - var Level = $.extend({ - dimension : Dimension, - hierarchy : Hierarchy, - members : [], - properties : [], - depth : 0, - calculated : false, - cardinality : [], - levelType : { - REGULAR : "", - ALL : "", - NULL : "", - TIME_YEARS : "", - TIME_HALF_YEAR : "", - TIME_QUARTERS : "", - TIME_MONTHS : "", - TIME_WEEKS : "", - TIME_DAYS : "", - TIME_HOURS : "", - TIME_MINUTES : "", - TIME_SECONDS : "", - TIME_UNDEFINED : "", - GEO_CONTINENT : "", - GEO_REGION : "", - GEO_COUNTRY : "", - GEO_STATE_OR_PROVINCE : "", - GEO_COUNTY : "", - GEO_CITY : "", - GEO_POSTALCODE : "", - GEO_POINT : "", - ORG_UNIT : "", - BOM_RESOURCE : "", - QUANTITATIVE : "", - ACCOUNT : "", - CUSTOMER : "", - CUSTOMER_GROUP : "", - CUSTOMER_HOUSEHOLD : "", - PRODUCT : "", - PRODUCT_GROUP : "", - SCENARIO : "", - UTILITY : "", - PERSON : "", - COMPANY : "", - CURRENCY_SOURCE : "", - CURRENCY_DESTINATION : "", - CHANNEL : "", - REPRESENTATIVE : "", - PROMOTION : "" - } - }, MetadataElement); - - var Member = $.extend({ - dimension : Dimension, - hierarchy : Hierarchy, - level : Level, - all : false, - calculated : false, - calculatedInQuery : false, - hidden : false, - solveOrder : 0, - ordinal : 0, - depth : 0, - childMemberCount : 0, - ancestorMembers : [], - childMembers : [], - properties : [] - }, MetadataElement); - - Member.parentMember = Member; - Member.dataMember = Member; - - Hierarchy.defaultMember = Member; - - var Cell = { - coordinateList : [], - ordinal : 0, - value : "", - doubleValue : "", - errorText : "", - empty : false, - error : false, - "null" : false, - formattedValue : "" - }; - - var ELContext = { - cube : Cube, - catalog : Catalog, - model : Model, - roleName : "", - locale : Locale, - memberUtils : { - lookupMember : function(uniqueName) { - } - }, - axis : Axis, - position : Position, - columnPosition : Position, - rowPosition : Position, - hierarchy : Hierarchy, - level : Level, - member : Member, - cell : Cell, - cellType : { - Value : "", - Header : "", - Title : "", - Aggregation : "", - None : "" - }, - rowIndex : 0, - columnIndex : 0, - rowSpan : 0, - columnSpan : 0, - rowCount : 0, - columnCount : 0, - rowHeaderCount : 0, - columnHeaderCount : 0, - attributes : {} - }; - - function getCompletions(token, context, keywords, options) { - var found = [], start = token.string; - - function maybeAdd(str) { - if (str.indexOf(start) == 0 && !arrayContains(found, str)) { - found.push(str); - } - } - - function gatherCompletions(obj) { - for ( var name in obj) { - maybeAdd(name); - } - } - - if (context) { - var base = ELContext; - - while (base != null && context.length) { - base = base[context.pop().string]; - } - - gatherCompletions(base); - } else { - gatherCompletions(ELContext); - - forEach(keywords, maybeAdd); - } - - return found; - } -})(); +CodeMirror + .defineMode( + "mdx", + function (config, parserConfig) { + var keywords = parserConfig.keywords, functions = parserConfig.functions, properties = parserConfig.properties, multiLineStrings = parserConfig.multiLineStrings; + var isOperatorChar = /[+\-*&%=<>!?:\/|]/; + function chain(stream, state, f) { + state.tokenize = f; + return f(stream, state); + } + + function ret(tp, style) { + type = tp; + return style; + } + + function tokenBase(stream, state) { + var ch = stream.next(); + // start of string? + if (ch === '"' || ch === "'") + return chain(stream, state, tokenString(ch)); + // is it one of the special signs {}().,;? Seperator? + else if (/[{}\(\),;\.]/.test(ch)) + return ret("bracket", "bracket"); + // start of a number value? + else if (/\d/.test(ch)) { + stream.eatWhile(/[\w\.]/); + return ret("number", "number"); + } + // multi line comment or simple operator? + else if (ch === "/") { + if (stream.eat("*")) { + return chain(stream, state, tokenComment); + } else { + stream.eatWhile(isOperatorChar); + return ret("operator", "operator"); + } + } + // single line comment or simple operator? + else if (ch === "-") { + if (stream.eat("-")) { + stream.skipToEnd(); + return ret("comment", "comment"); + } else { + stream.eatWhile(isOperatorChar); + return ret("operator", "operator"); + } + } + // is it an identifier? + else if (ch === "[") { + return chain(stream, state, tokenString("]")); + } + // is it a operator? + else if (isOperatorChar.test(ch)) { + stream.eatWhile(isOperatorChar); + return ret("operator", "operator"); + } else { + // get the whole word + stream.eatWhile(/[\w\$_]/); + // is it one of the listed keywords? + if (keywords + && keywords.propertyIsEnumerable(stream + .current().toLowerCase())) + return ret("keyword", "keyword"); + // is it one of the listed functions? + if (functions + && functions.propertyIsEnumerable(stream + .current().toLowerCase())) + return ret("keyword", "builtin"); + // is it one of the listed types? + if (properties + && properties.propertyIsEnumerable(stream + .current().toLowerCase())) + return ret("keyword", "variable-2"); + // default: just a "variable" + return ret("word", "variable"); + } + } + + function tokenString(quote) { + return function (stream, state) { + var escaped = false, next, end = false; + while ((next = stream.next()) !== null) { + if (next === quote && !escaped) { + end = true; + break; + } + escaped = !escaped && next === "\\"; + } + if (end || !(escaped || multiLineStrings)) + state.tokenize = tokenBase; + return ret("string", "qualifier"); + }; + } + + function tokenComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch === "/" && maybeEnd) { + state.tokenize = tokenBase; + break; + } + maybeEnd = (ch === "*"); + } + return ret("comment", "comment"); + } + + // Interface + return { + startState: function (basecolumn) { + return { + tokenize: tokenBase, + startOfLine: true + }; + }, + + token: function (stream, state) { + if (stream.eatSpace()) + return null; + var style = state.tokenize(stream, state); + return style; + } + }; + }); + +(function () { + function keywords(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) + obj[words[i]] = true; + return obj; + } + + var mdxKeywords = "select from on columns rows where with not in properties"; + + var mdxFunctions = "hierarchize crossjoin union filter iif format exists except " + + "dateDiff dateAdd bottomCount bottomSum"; + + var mdxProperties = "null children descendants members firstChild firstSibling lastChild " + + "lastSibling parent name uniqueName nextMember hierarchy dimension currentMember " + + "defaultMember allMembers"; + + CodeMirror.defineMIME("text/x-mdx", { + name: "mdx", + keywords: keywords(mdxKeywords), + functions: keywords(mdxFunctions), + properties: keywords(mdxProperties) + }); +}()); + +CodeMirror + .defineMode( + "freemarker", + function (config, parserConfig) { + var keywords = parserConfig.keywords, functions = parserConfig.functions, properties = parserConfig.properties, multiLineStrings = parserConfig.multiLineStrings; + var isOperatorChar = /[+\-*&%=<>!?:\/|]/; + function chain(stream, state, f) { + state.tokenize = f; + return f(stream, state); + } + + function ret(tp, style) { + type = tp; + return style; + } + + function tokenBase(stream, state) { + var ch = stream.next(); + // start of string? + if (ch === '"' || ch === "'") + return chain(stream, state, tokenString(ch)); + // is it one of the special signs {}().,;? Seperator? + else if (/[<>\[\]{}\(\),;\.]/.test(ch)) + return ret("bracket", "bracket"); + // start of a number value? + else if (/\d/.test(ch)) { + stream.eatWhile(/[\w\.]/); + return ret("number", "number"); + } + // is it a operator? + else if (isOperatorChar.test(ch)) { + stream.eatWhile(isOperatorChar); + return ret("operator", "operator"); + } else { + // get the whole word + stream.eatWhile(/[\w\$_]/); + // is it one of the listed keywords? + if (keywords + && keywords.propertyIsEnumerable(stream + .current().toLowerCase())) + return ret("keyword", "keyword"); + // is it one of the listed functions? + if (functions + && functions.propertyIsEnumerable(stream + .current().toLowerCase())) + return ret("keyword", "builtin"); + // is it one of the listed types? + if (properties + && properties.propertyIsEnumerable(stream + .current().toLowerCase())) + return ret("keyword", "variable-2"); + // default: just a "variable" + return ret("word", "variable"); + } + } + + function tokenString(quote) { + return function (stream, state) { + var escaped = false, next, end = false; + while ((next = stream.next()) !== null) { + if (next === quote && !escaped) { + end = true; + break; + } + escaped = !escaped && next === "\\"; + } + if (end || !(escaped || multiLineStrings)) + state.tokenize = tokenBase; + return ret("string", "qualifier"); + }; + } + + // Interface + return { + startState: function (basecolumn) { + return { + tokenize: tokenBase, + startOfLine: true + }; + }, + + token: function (stream, state) { + if (stream.eatSpace()) + return null; + var style = state.tokenize(stream, state); + return style; + } + }; + }); + +(function () { + function keywords(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) + obj[words[i]] = true; + return obj; + } + + var mdxKeywords = "#if #list #assign #else as"; + + var mdxFunctions = "html cap_first lower_case upper_case trim size int repeat"; + + var mdxProperties = "member level hierarchy model cube catalog locale dimension position " + + "columnPosition rowPosition cell cellType property roleName memberUtils attributes " + + "axis rowIndex rowIndex rowSpan columnSpan rowCount columnCount rowHeaderCount columnHeaderCount"; + + CodeMirror.defineMIME("text/x-freemarker", { + name: "freemarker", + keywords: keywords(mdxKeywords), + functions: keywords(mdxFunctions), + properties: keywords(mdxProperties) + }); +}()); + +(function () { + CodeMirror.pivot4jHint = function (editor, options) { + var keywords = []; + + return scriptHint(editor, keywords, function (e, cur) { + return e.getTokenAt(cur); + }, options); + }; + + function Pos(line, ch) { + if (!(this instanceof Pos)) + return new Pos(line, ch); + this.line = line; + this.ch = ch; + } + + function forEach(arr, f) { + for (var i = 0, e = arr.length; i < e; ++i) { + f(arr[i]); + } + } + + function arrayContains(arr, item) { + if (!Array.prototype.indexOf) { + var i = arr.length; + while (i--) { + if (arr[i] === item) { + return true; + } + } + return false; + } + return arr.indexOf(item) !== -1; + } + + function scriptHint(editor, keywords, getToken, options) { + var result = []; + + // Find the token at the cursor + var cur = editor.getCursor(); + var token = getToken(editor, cur); + + token.state = CodeMirror.innerMode(editor.getMode(), token.state).state; + + var ch = token.string.charAt(0); + + if (ch === "<" || ch === "/") { + if (ch === "<") { + result = ["<#if ", "<#list ", "<#assign ", "<#else>"]; + } else if (getToken(editor, Pos(cur.line, token.start)).string + .charAt(0) === "<") { + result = ["/#if>", "/#list>", "/#assign>"]; + } + } else { + var tprop = token; + + // If it's not a 'word-style' token, ignore the token. + if (!/^[\w$_]*$/.test(token.string)) { + token = tprop = { + start: cur.ch, + end: cur.ch, + string: "", + state: token.state, + type: token.string === "." ? "property" : null + }; + } + + var context = []; + + while (tprop) { + tprop = getToken(editor, Pos(cur.line, tprop.start)); + + if (tprop.string !== ".") { + break; + } + + tprop = getToken(editor, Pos(cur.line, tprop.start)); + + context.push(tprop); + } + + result = getCompletions(token, context, keywords, options); + } + + return { + list: result, + from: Pos(cur.line, token.start), + to: Pos(cur.line, token.end) + }; + } + + var MetadataElement = { + name: "", + uniqueName: "", + caption: "", + description: "", + visible: true + }; + + var Database = { + name: "", + description: "", + catalogs: [], + dataSourceInfo: "", + olapConnection: {}, + providerName: "", + URL: "" + }; + + var Catalog = { + name: "", + schemas: [], + database: Database + }; + + var Schema = { + name: "", + catalog: Catalog, + cubes: [], + sharedDimensions: [], + supportedLocales: [] + }; + + var Cube = $.extend({ + hierarchies: [], + dimensions: [], + sets: [], + measures: [], + supportedLocales: [], + schema: Schema + }, MetadataElement); + + var Locale = { + language: "", + country: "", + variant: "" + }; + + var Model = { + cube: Cube, + roleName: "", + locale: Locale, + cellSet: {} + }; + + var Axis = { + axisOrdinal: 0 + }; + + var Position = { + ordinal: 0, + members: [] + }; + + var Dimension = $.extend({ + dimensionType: { + UNKNOWN: "", + TIME: "", + MEASURE: "", + OTHER: "", + QUANTITATIVE: "", + ACCOUNTS: "", + CUSTOMERS: "", + PRODUCTS: "", + SCENARIO: "", + UTILITY: "", + CURRENCY: "", + RATES: "", + CHANNEL: "", + PROMOTION: "", + ORGANIZATION: "", + BILL_OF_MATERIALS: "", + GEOGRAPHY: "" + }, + hierarchies: [] + }, MetadataElement); + + var Hierarchy = $.extend({ + dimension: Dimension, + levels: [], + rootMembers: [] + }, MetadataElement); + + Dimension.defaultHierarchy = Hierarchy; + + var Level = $.extend({ + dimension: Dimension, + hierarchy: Hierarchy, + members: [], + properties: [], + depth: 0, + calculated: false, + cardinality: [], + levelType: { + REGULAR: "", + ALL: "", + NULL: "", + TIME_YEARS: "", + TIME_HALF_YEAR: "", + TIME_QUARTERS: "", + TIME_MONTHS: "", + TIME_WEEKS: "", + TIME_DAYS: "", + TIME_HOURS: "", + TIME_MINUTES: "", + TIME_SECONDS: "", + TIME_UNDEFINED: "", + GEO_CONTINENT: "", + GEO_REGION: "", + GEO_COUNTRY: "", + GEO_STATE_OR_PROVINCE: "", + GEO_COUNTY: "", + GEO_CITY: "", + GEO_POSTALCODE: "", + GEO_POINT: "", + ORG_UNIT: "", + BOM_RESOURCE: "", + QUANTITATIVE: "", + ACCOUNT: "", + CUSTOMER: "", + CUSTOMER_GROUP: "", + CUSTOMER_HOUSEHOLD: "", + PRODUCT: "", + PRODUCT_GROUP: "", + SCENARIO: "", + UTILITY: "", + PERSON: "", + COMPANY: "", + CURRENCY_SOURCE: "", + CURRENCY_DESTINATION: "", + CHANNEL: "", + REPRESENTATIVE: "", + PROMOTION: "" + } + }, MetadataElement); + + var Member = $.extend({ + dimension: Dimension, + hierarchy: Hierarchy, + level: Level, + all: false, + calculated: false, + calculatedInQuery: false, + hidden: false, + solveOrder: 0, + ordinal: 0, + depth: 0, + childMemberCount: 0, + ancestorMembers: [], + childMembers: [], + properties: [] + }, MetadataElement); + + Member.parentMember = Member; + Member.dataMember = Member; + + Hierarchy.defaultMember = Member; + + var Cell = { + coordinateList: [], + ordinal: 0, + value: "", + doubleValue: "", + errorText: "", + empty: false, + error: false, + "null": false, + formattedValue: "" + }; + + var ELContext = { + cube: Cube, + catalog: Catalog, + model: Model, + roleName: "", + locale: Locale, + memberUtils: { + lookupMember: function (uniqueName) { + } + }, + axis: Axis, + position: Position, + columnPosition: Position, + rowPosition: Position, + hierarchy: Hierarchy, + level: Level, + member: Member, + cell: Cell, + cellType: { + Value: "", + Header: "", + Title: "", + Aggregation: "", + None: "" + }, + rowIndex: 0, + columnIndex: 0, + rowSpan: 0, + columnSpan: 0, + rowCount: 0, + columnCount: 0, + rowHeaderCount: 0, + columnHeaderCount: 0, + attributes: {} + }; + + function getCompletions(token, context, keywords, options) { + var found = [], start = token.string; + + function maybeAdd(str) { + if (str.indexOf(start) === 0 && !arrayContains(found, str)) { + found.push(str); + } + } + + function gatherCompletions(obj) { + for (var name in obj) { + maybeAdd(name); + } + } + + if (context) { + var base = ELContext; + + while (base !== null && context.length) { + base = base[context.pop().string]; + } + + gatherCompletions(base); + } else { + gatherCompletions(ELContext); + + forEach(keywords, maybeAdd); + } + + return found; + } +})(); diff --git a/pivot4j-analytics/src/main/webapp/resources/pivot4j/js/colorpicker.js b/pivot4j-analytics/src/main/webapp/resources/pivot4j/js/colorpicker.js index e77e0e99..149ad5fe 100644 --- a/pivot4j-analytics/src/main/webapp/resources/pivot4j/js/colorpicker.js +++ b/pivot4j-analytics/src/main/webapp/resources/pivot4j/js/colorpicker.js @@ -1,25 +1,25 @@ PrimeFaces.widget.AjaxColorPicker = PrimeFaces.widget.ColorPicker.extend({ - bindCallbacks_ : PrimeFaces.widget.ColorPicker.prototype.bindCallbacks, + bindCallbacks_: PrimeFaces.widget.ColorPicker.prototype.bindCallbacks, - bindCallbacks : function() { - var _self = this; + bindCallbacks: function () { + var _self = this; - this.bindCallbacks_.apply(this); + this.bindCallbacks_.apply(this); - this.cfg.onChange_ = this.cfg.onChange; - this.cfg.onChange = function(hsb, hex, rgb) { - _self.cfg.onChange_.call(_self, hsb, hex, rgb); - _self.fireChangeEvent(hex); - }; - }, + this.cfg.onChange_ = this.cfg.onChange; + this.cfg.onChange = function (hsb, hex, rgb) { + _self.cfg.onChange_.call(_self, hsb, hex, rgb); + _self.fireChangeEvent(hex); + }; + }, - fireChangeEvent : function(hex) { - if (this.cfg.behaviors) { - var behavior = this.cfg.behaviors["change"]; + fireChangeEvent: function (hex) { + if (this.cfg.behaviors) { + var behavior = this.cfg.behaviors["change"]; - if (behavior) { - behavior.call(this); - } - } - } + if (behavior) { + behavior.call(this); + } + } + } }); \ No newline at end of file diff --git a/pivot4j-analytics/src/main/webapp/resources/pivot4j/js/jquery.ui.tabs.js b/pivot4j-analytics/src/main/webapp/resources/pivot4j/js/jquery.ui.tabs.js index b37858e4..5f6f7249 100644 --- a/pivot4j-analytics/src/main/webapp/resources/pivot4j/js/jquery.ui.tabs.js +++ b/pivot4j-analytics/src/main/webapp/resources/pivot4j/js/jquery.ui.tabs.js @@ -1,846 +1,888 @@ -/*! - * jQuery UI Tabs 1.10.3 - * http://jqueryui.com - * - * Copyright 2013 jQuery Foundation and other contributors - * Released under the MIT license. - * http://jquery.org/license - * - * http://api.jqueryui.com/tabs/ - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - */ -(function( $, undefined ) { - -var tabId = 0, - rhash = /#.*$/; - -function getNextTabId() { - return ++tabId; -} - -function isLocal( anchor ) { - return anchor.hash.length > 1 && - decodeURIComponent( anchor.href.replace( rhash, "" ) ) === - decodeURIComponent( location.href.replace( rhash, "" ) ); -} - -$.widget( "ui.tabs", { - version: "1.10.3", - delay: 300, - options: { - active: null, - collapsible: false, - event: "click", - heightStyle: "content", - hide: null, - show: null, - - // callbacks - activate: null, - beforeActivate: null, - beforeLoad: null, - load: null - }, - - _create: function() { - var that = this, - options = this.options; - - this.running = false; - - this.element - .addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" ) - .toggleClass( "ui-tabs-collapsible", options.collapsible ) - // Prevent users from focusing disabled tabs via click - .delegate( ".ui-tabs-nav > li", "mousedown" + this.eventNamespace, function( event ) { - if ( $( this ).is( ".ui-state-disabled" ) ) { - event.preventDefault(); - } - }) - // support: IE <9 - // Preventing the default action in mousedown doesn't prevent IE - // from focusing the element, so if the anchor gets focused, blur. - // We don't have to worry about focusing the previously focused - // element since clicking on a non-focusable element should focus - // the body anyway. - .delegate( ".ui-tabs-anchor", "focus" + this.eventNamespace, function() { - if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) { - this.blur(); - } - }); - - this._processTabs(); - options.active = this._initialActive(); - - // Take disabling tabs via class attribute from HTML - // into account and update option properly. - if ( $.isArray( options.disabled ) ) { - options.disabled = $.unique( options.disabled.concat( - $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) { - return that.tabs.index( li ); - }) - ) ).sort(); - } - - // check for length avoids error when initializing empty list - if ( this.options.active !== false && this.anchors.length ) { - this.active = this._findActive( options.active ); - } else { - this.active = $(); - } - - this._refresh(); - - if ( this.active.length ) { - this.load( options.active ); - } - }, - - _initialActive: function() { - var active = this.options.active, - collapsible = this.options.collapsible, - locationHash = location.hash.substring( 1 ); - - if ( active === null ) { - // check the fragment identifier in the URL - if ( locationHash ) { - this.tabs.each(function( i, tab ) { - if ( $( tab ).attr( "aria-controls" ) === locationHash ) { - active = i; - return false; - } - }); - } - - // check for a tab marked active via a class - if ( active === null ) { - active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) ); - } - - // no active tab, set to false - if ( active === null || active === -1 ) { - active = this.tabs.length ? 0 : false; - } - } - - // handle numbers: negative, out of range - if ( active !== false ) { - active = this.tabs.index( this.tabs.eq( active ) ); - if ( active === -1 ) { - active = collapsible ? false : 0; - } - } - - // don't allow collapsible: false and active: false - if ( !collapsible && active === false && this.anchors.length ) { - active = 0; - } - - return active; - }, - - _getCreateEventData: function() { - return { - tab: this.active, - panel: !this.active.length ? $() : this._getPanelForTab( this.active ) - }; - }, - - _tabKeydown: function( event ) { - /*jshint maxcomplexity:15*/ - var focusedTab = $( this.document[0].activeElement ).closest( "li" ), - selectedIndex = this.tabs.index( focusedTab ), - goingForward = true; - - if ( this._handlePageNav( event ) ) { - return; - } - - switch ( event.keyCode ) { - case $.ui.keyCode.RIGHT: - case $.ui.keyCode.DOWN: - selectedIndex++; - break; - case $.ui.keyCode.UP: - case $.ui.keyCode.LEFT: - goingForward = false; - selectedIndex--; - break; - case $.ui.keyCode.END: - selectedIndex = this.anchors.length - 1; - break; - case $.ui.keyCode.HOME: - selectedIndex = 0; - break; - case $.ui.keyCode.SPACE: - // Activate only, no collapsing - event.preventDefault(); - clearTimeout( this.activating ); - this._activate( selectedIndex ); - return; - case $.ui.keyCode.ENTER: - // Toggle (cancel delayed activation, allow collapsing) - event.preventDefault(); - clearTimeout( this.activating ); - // Determine if we should collapse or activate - this._activate( selectedIndex === this.options.active ? false : selectedIndex ); - return; - default: - return; - } - - // Focus the appropriate tab, based on which key was pressed - event.preventDefault(); - clearTimeout( this.activating ); - selectedIndex = this._focusNextTab( selectedIndex, goingForward ); - - // Navigating with control key will prevent automatic activation - if ( !event.ctrlKey ) { - // Update aria-selected immediately so that AT think the tab is already selected. - // Otherwise AT may confuse the user by stating that they need to activate the tab, - // but the tab will already be activated by the time the announcement finishes. - focusedTab.attr( "aria-selected", "false" ); - this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" ); - - this.activating = this._delay(function() { - this.option( "active", selectedIndex ); - }, this.delay ); - } - }, - - _panelKeydown: function( event ) { - if ( this._handlePageNav( event ) ) { - return; - } - - // Ctrl+up moves focus to the current tab - if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) { - event.preventDefault(); - this.active.focus(); - } - }, - - // Alt+page up/down moves focus to the previous/next tab (and activates) - _handlePageNav: function( event ) { - if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) { - this._activate( this._focusNextTab( this.options.active - 1, false ) ); - return true; - } - if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) { - this._activate( this._focusNextTab( this.options.active + 1, true ) ); - return true; - } - }, - - _findNextTab: function( index, goingForward ) { - var lastTabIndex = this.tabs.length - 1; - - function constrain() { - if ( index > lastTabIndex ) { - index = 0; - } - if ( index < 0 ) { - index = lastTabIndex; - } - return index; - } - - while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) { - index = goingForward ? index + 1 : index - 1; - } - - return index; - }, - - _focusNextTab: function( index, goingForward ) { - index = this._findNextTab( index, goingForward ); - this.tabs.eq( index ).focus(); - return index; - }, - - _setOption: function( key, value ) { - if ( key === "active" ) { - // _activate() will handle invalid values and update this.options - this._activate( value ); - return; - } - - if ( key === "disabled" ) { - // don't use the widget factory's disabled handling - this._setupDisabled( value ); - return; - } - - this._super( key, value); - - if ( key === "collapsible" ) { - this.element.toggleClass( "ui-tabs-collapsible", value ); - // Setting collapsible: false while collapsed; open first panel - if ( !value && this.options.active === false ) { - this._activate( 0 ); - } - } - - if ( key === "event" ) { - this._setupEvents( value ); - } - - if ( key === "heightStyle" ) { - this._setupHeightStyle( value ); - } - }, - - _tabId: function( tab ) { - return tab.attr( "aria-controls" ) || "ui-tabs-" + getNextTabId(); - }, - - _sanitizeSelector: function( hash ) { - return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : ""; - }, - - refresh: function() { - var options = this.options, - lis = this.tablist.children( ":has(a[href])" ); - - // get disabled tabs from class attribute from HTML - // this will get converted to a boolean if needed in _refresh() - options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) { - return lis.index( tab ); - }); - - this._processTabs(); - - // was collapsed or no tabs - if ( options.active === false || !this.anchors.length ) { - options.active = false; - this.active = $(); - // was active, but active tab is gone - } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) { - // all remaining tabs are disabled - if ( this.tabs.length === options.disabled.length ) { - options.active = false; - this.active = $(); - // activate previous tab - } else { - this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) ); - } - // was active, active tab still exists - } else { - // make sure active index is correct - options.active = this.tabs.index( this.active ); - } - - this._refresh(); - }, - - _refresh: function() { - this._setupDisabled( this.options.disabled ); - this._setupEvents( this.options.event ); - this._setupHeightStyle( this.options.heightStyle ); - - this.tabs.not( this.active ).attr({ - "aria-selected": "false", - tabIndex: -1 - }); - this.panels.not( this._getPanelForTab( this.active ) ) - .hide() - .attr({ - "aria-expanded": "false", - "aria-hidden": "true" - }); - - // Make sure one tab is in the tab order - if ( !this.active.length ) { - this.tabs.eq( 0 ).attr( "tabIndex", 0 ); - } else { - this.active - .addClass( "ui-tabs-active ui-state-active" ) - .attr({ - "aria-selected": "true", - tabIndex: 0 - }); - this._getPanelForTab( this.active ) - .show() - .attr({ - "aria-expanded": "true", - "aria-hidden": "false" - }); - } - }, - - _processTabs: function() { - var that = this; - - this.tablist = this._getList() - .addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" ) - .attr( "role", "tablist" ); - - this.tabs = this.tablist.find( "> li:has(a[href])" ) - .addClass( "ui-state-default ui-corner-top" ) - .attr({ - role: "tab", - tabIndex: -1 - }); - - this.anchors = this.tabs.map(function() { - return $( "a", this )[ 0 ]; - }) - .addClass( "ui-tabs-anchor" ) - .attr({ - role: "presentation", - tabIndex: -1 - }); - - this.panels = $(); - - this.anchors.each(function( i, anchor ) { - var selector, panel, panelId, - anchorId = $( anchor ).uniqueId().attr( "id" ), - tab = $( anchor ).closest( "li" ), - originalAriaControls = tab.attr( "aria-controls" ); - - // inline tab - if ( isLocal( anchor ) ) { - selector = anchor.hash; - panel = that.element.find( that._sanitizeSelector( selector ) ); - // remote tab - } else { - panelId = that._tabId( tab ); - selector = "#" + panelId; - panel = that.element.find( selector ); - if ( !panel.length ) { - panel = that._createPanel( panelId ); - panel.insertAfter( that.panels[ i - 1 ] || that.tablist ); - } - panel.attr( "aria-live", "polite" ); - } - - if ( panel.length) { - that.panels = that.panels.add( panel ); - } - if ( originalAriaControls ) { - tab.data( "ui-tabs-aria-controls", originalAriaControls ); - } - tab.attr({ - "aria-controls": selector.substring( 1 ), - "aria-labelledby": anchorId - }); - panel.attr( "aria-labelledby", anchorId ); - }); - - this.panels - .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ) - .attr( "role", "tabpanel" ); - }, - - // allow overriding how to find the list for rare usage scenarios (#7715) - _getList: function() { - return this.element.find( "ol,ul" ).eq( 0 ); - }, - - _createPanel: function( id ) { - return $( "
      " ) - .attr( "id", id ) - .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ) - .data( "ui-tabs-destroy", true ); - }, - - _setupDisabled: function( disabled ) { - if ( $.isArray( disabled ) ) { - if ( !disabled.length ) { - disabled = false; - } else if ( disabled.length === this.anchors.length ) { - disabled = true; - } - } - - // disable tabs - for ( var i = 0, li; ( li = this.tabs[ i ] ); i++ ) { - if ( disabled === true || $.inArray( i, disabled ) !== -1 ) { - $( li ) - .addClass( "ui-state-disabled" ) - .attr( "aria-disabled", "true" ); - } else { - $( li ) - .removeClass( "ui-state-disabled" ) - .removeAttr( "aria-disabled" ); - } - } - - this.options.disabled = disabled; - }, - - _setupEvents: function( event ) { - var events = { - click: function( event ) { - event.preventDefault(); - } - }; - if ( event ) { - $.each( event.split(" "), function( index, eventName ) { - events[ eventName ] = "_eventHandler"; - }); - } - - this._off( this.anchors.add( this.tabs ).add( this.panels ) ); - this._on( this.anchors, events ); - this._on( this.tabs, { keydown: "_tabKeydown" } ); - this._on( this.panels, { keydown: "_panelKeydown" } ); - - this._focusable( this.tabs ); - this._hoverable( this.tabs ); - }, - - _setupHeightStyle: function( heightStyle ) { - var maxHeight, - parent = this.element.parent(); - - if ( heightStyle === "fill" ) { - maxHeight = parent.height(); - maxHeight -= this.element.outerHeight() - this.element.height(); - - this.element.siblings( ":visible" ).each(function() { - var elem = $( this ), - position = elem.css( "position" ); - - if ( position === "absolute" || position === "fixed" ) { - return; - } - maxHeight -= elem.outerHeight( true ); - }); - - this.element.children().not( this.panels ).each(function() { - maxHeight -= $( this ).outerHeight( true ); - }); - - this.panels.each(function() { - $( this ).height( Math.max( 0, maxHeight - - $( this ).innerHeight() + $( this ).height() ) ); - }) - .css( "overflow", "auto" ); - } else if ( heightStyle === "auto" ) { - maxHeight = 0; - this.panels.each(function() { - maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() ); - }).height( maxHeight ); - } - }, - - _eventHandler: function( event ) { - var options = this.options, - active = this.active, - anchor = $( event.currentTarget ), - tab = anchor.closest( "li" ), - clickedIsActive = tab[ 0 ] === active[ 0 ], - collapsing = clickedIsActive && options.collapsible, - toShow = collapsing ? $() : this._getPanelForTab( tab ), - toHide = !active.length ? $() : this._getPanelForTab( active ), - eventData = { - oldTab: active, - oldPanel: toHide, - newTab: collapsing ? $() : tab, - newPanel: toShow - }; - - event.preventDefault(); - - if ( tab.hasClass( "ui-state-disabled" ) || - // tab is already loading - tab.hasClass( "ui-tabs-loading" ) || - // can't switch durning an animation - this.running || - // click on active header, but not collapsible - ( clickedIsActive && !options.collapsible ) || - // allow canceling activation - ( this._trigger( "beforeActivate", event, eventData ) === false ) ) { - return; - } - - options.active = collapsing ? false : this.tabs.index( tab ); - - this.active = clickedIsActive ? $() : tab; - if ( this.xhr ) { - this.xhr.abort(); - } - - if ( !toHide.length && !toShow.length ) { - $.error( "jQuery UI Tabs: Mismatching fragment identifier." ); - } - - if ( toShow.length ) { - this.load( this.tabs.index( tab ), event ); - } - this._toggle( event, eventData ); - }, - - // handles show/hide for selecting tabs - _toggle: function( event, eventData ) { - var that = this, - toShow = eventData.newPanel, - toHide = eventData.oldPanel; - - this.running = true; - - function complete() { - that.running = false; - that._trigger( "activate", event, eventData ); - } - - function show() { - eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" ); - - if ( toShow.length && that.options.show ) { - that._show( toShow, that.options.show, complete ); - } else { - toShow.show(); - complete(); - } - } - - // start out by hiding, then showing, then completing - if ( toHide.length && this.options.hide ) { - this._hide( toHide, this.options.hide, function() { - eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" ); - show(); - }); - } else { - eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" ); - toHide.hide(); - show(); - } - - toHide.attr({ - "aria-expanded": "false", - "aria-hidden": "true" - }); - eventData.oldTab.attr( "aria-selected", "false" ); - // If we're switching tabs, remove the old tab from the tab order. - // If we're opening from collapsed state, remove the previous tab from the tab order. - // If we're collapsing, then keep the collapsing tab in the tab order. - if ( toShow.length && toHide.length ) { - eventData.oldTab.attr( "tabIndex", -1 ); - } else if ( toShow.length ) { - this.tabs.filter(function() { - return $( this ).attr( "tabIndex" ) === 0; - }) - .attr( "tabIndex", -1 ); - } - - toShow.attr({ - "aria-expanded": "true", - "aria-hidden": "false" - }); - eventData.newTab.attr({ - "aria-selected": "true", - tabIndex: 0 - }); - }, - - _activate: function( index ) { - var anchor, - active = this._findActive( index ); - - // trying to activate the already active panel - if ( active[ 0 ] === this.active[ 0 ] ) { - return; - } - - // trying to collapse, simulate a click on the current active header - if ( !active.length ) { - active = this.active; - } - - anchor = active.find( ".ui-tabs-anchor" )[ 0 ]; - this._eventHandler({ - target: anchor, - currentTarget: anchor, - preventDefault: $.noop - }); - }, - - _findActive: function( index ) { - return index === false ? $() : this.tabs.eq( index ); - }, - - _getIndex: function( index ) { - // meta-function to give users option to provide a href string instead of a numerical index. - if ( typeof index === "string" ) { - index = this.anchors.index( this.anchors.filter( "[href$='" + index + "']" ) ); - } - - return index; - }, - - _destroy: function() { - if ( this.xhr ) { - this.xhr.abort(); - } - - this.element.removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" ); - - this.tablist - .removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" ) - .removeAttr( "role" ); - - this.anchors - .removeClass( "ui-tabs-anchor" ) - .removeAttr( "role" ) - .removeAttr( "tabIndex" ) - .removeUniqueId(); - - this.tabs.add( this.panels ).each(function() { - if ( $.data( this, "ui-tabs-destroy" ) ) { - $( this ).remove(); - } else { - $( this ) - .removeClass( "ui-state-default ui-state-active ui-state-disabled " + - "ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel" ) - .removeAttr( "tabIndex" ) - .removeAttr( "aria-live" ) - .removeAttr( "aria-busy" ) - .removeAttr( "aria-selected" ) - .removeAttr( "aria-labelledby" ) - .removeAttr( "aria-hidden" ) - .removeAttr( "aria-expanded" ) - .removeAttr( "role" ); - } - }); - - this.tabs.each(function() { - var li = $( this ), - prev = li.data( "ui-tabs-aria-controls" ); - if ( prev ) { - li - .attr( "aria-controls", prev ) - .removeData( "ui-tabs-aria-controls" ); - } else { - li.removeAttr( "aria-controls" ); - } - }); - - this.panels.show(); - - if ( this.options.heightStyle !== "content" ) { - this.panels.css( "height", "" ); - } - }, - - enable: function( index ) { - var disabled = this.options.disabled; - if ( disabled === false ) { - return; - } - - if ( index === undefined ) { - disabled = false; - } else { - index = this._getIndex( index ); - if ( $.isArray( disabled ) ) { - disabled = $.map( disabled, function( num ) { - return num !== index ? num : null; - }); - } else { - disabled = $.map( this.tabs, function( li, num ) { - return num !== index ? num : null; - }); - } - } - this._setupDisabled( disabled ); - }, - - disable: function( index ) { - var disabled = this.options.disabled; - if ( disabled === true ) { - return; - } - - if ( index === undefined ) { - disabled = true; - } else { - index = this._getIndex( index ); - if ( $.inArray( index, disabled ) !== -1 ) { - return; - } - if ( $.isArray( disabled ) ) { - disabled = $.merge( [ index ], disabled ).sort(); - } else { - disabled = [ index ]; - } - } - this._setupDisabled( disabled ); - }, - - load: function( index, event ) { - index = this._getIndex( index ); - var that = this, - tab = this.tabs.eq( index ), - anchor = tab.find( ".ui-tabs-anchor" ), - panel = this._getPanelForTab( tab ), - eventData = { - tab: tab, - panel: panel - }; - - // not remote - if ( isLocal( anchor[ 0 ] ) ) { - return; - } - - this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) ); - - // support: jQuery <1.8 - // jQuery <1.8 returns false if the request is canceled in beforeSend, - // but as of 1.8, $.ajax() always returns a jqXHR object. - if ( this.xhr && this.xhr.statusText !== "canceled" ) { - tab.addClass( "ui-tabs-loading" ); - panel.attr( "aria-busy", "true" ); - - this.xhr - .success(function( response ) { - // support: jQuery <1.8 - // http://bugs.jquery.com/ticket/11778 - setTimeout(function() { - panel.html( response ); - that._trigger( "load", event, eventData ); - }, 1 ); - }) - .complete(function( jqXHR, status ) { - // support: jQuery <1.8 - // http://bugs.jquery.com/ticket/11778 - setTimeout(function() { - if ( status === "abort" ) { - that.panels.stop( false, true ); - } - - tab.removeClass( "ui-tabs-loading" ); - panel.removeAttr( "aria-busy" ); - - if ( jqXHR === that.xhr ) { - delete that.xhr; - } - }, 1 ); - }); - } - }, - - _ajaxSettings: function( anchor, event, eventData ) { - var that = this; - return { - url: anchor.attr( "href" ), - beforeSend: function( jqXHR, settings ) { - return that._trigger( "beforeLoad", event, - $.extend( { jqXHR : jqXHR, ajaxSettings: settings }, eventData ) ); - } - }; - }, - - _getPanelForTab: function( tab ) { - var id = $( tab ).attr( "aria-controls" ); - return this.element.find( this._sanitizeSelector( "#" + id ) ); - } -}); - -})( jQuery ); +/*! jQuery UI - v1.12.1 - 2019-02-24 +* http://jqueryui.com +* Includes: widget.js, position.js, data.js, disable-selection.js, focusable.js, form-reset-mixin.js, jquery-1-7.js, keycode.js, labels.js, scroll-parent.js, tabbable.js, unique-id.js, widgets/draggable.js, widgets/droppable.js, widgets/resizable.js, widgets/selectable.js, widgets/sortable.js, widgets/accordion.js, widgets/autocomplete.js, widgets/button.js, widgets/checkboxradio.js, widgets/controlgroup.js, widgets/datepicker.js, widgets/dialog.js, widgets/menu.js, widgets/mouse.js, widgets/progressbar.js, widgets/selectmenu.js, widgets/slider.js, widgets/spinner.js, widgets/tabs.js, widgets/tooltip.js, effect.js, effects/effect-blind.js, effects/effect-bounce.js, effects/effect-clip.js, effects/effect-drop.js, effects/effect-explode.js, effects/effect-fade.js, effects/effect-fold.js, effects/effect-highlight.js, effects/effect-puff.js, effects/effect-pulsate.js, effects/effect-scale.js, effects/effect-shake.js, effects/effect-size.js, effects/effect-slide.js, effects/effect-transfer.js +* Copyright jQuery Foundation and other contributors; Licensed MIT */ +(function ($, undefined) { + + var tabId = 0, + rhash = /#.*$/; + + function getNextTabId() { + return ++tabId; + } + + function isLocal(anchor) { + return anchor.hash.length > 1 && + decodeURIComponent(anchor.href.replace(rhash, "")) === + decodeURIComponent(location.href.replace(rhash, "")); + } + + $.widget("ui.tabs", { + version: "1.12.1", + delay: 300, + options: { + active: null, + classes: { + "ui-tabs": "ui-corner-all", + "ui-tabs-nav": "ui-corner-all", + "ui-tabs-panel": "ui-corner-bottom", + "ui-tabs-tab": "ui-corner-top" + }, + collapsible: false, + event: "click", + heightStyle: "content", + hide: null, + show: null, + + // Callbacks + activate: null, + beforeActivate: null, + beforeLoad: null, + load: null + }, + + _isLocal: (function () { + var rhash = /#.*$/; + + return function (anchor) { + var anchorUrl, locationUrl; + + anchorUrl = anchor.href.replace(rhash, ""); + locationUrl = location.href.replace(rhash, ""); + + // Decoding may throw an error if the URL isn't UTF-8 (#9518) + try { + anchorUrl = decodeURIComponent(anchorUrl); + } catch (error) { + } + try { + locationUrl = decodeURIComponent(locationUrl); + } catch (error) { + } + + return anchor.hash.length > 1 && anchorUrl === locationUrl; + }; + })(), + + _create: function () { + var that = this, + options = this.options; + + this.running = false; + + this._addClass("ui-tabs", "ui-widget ui-widget-content"); + this._toggleClass("ui-tabs-collapsible", null, options.collapsible); + + this._processTabs(); + options.active = this._initialActive(); + + // Take disabling tabs via class attribute from HTML + // into account and update option properly. + if ($.isArray(options.disabled)) { + options.disabled = $.unique(options.disabled.concat( + $.map(this.tabs.filter(".ui-state-disabled"), function (li) { + return that.tabs.index(li); + }) + )).sort(); + } + + // Check for length avoids error when initializing empty list + if (this.options.active !== false && this.anchors.length) { + this.active = this._findActive(options.active); + } else { + this.active = $(); + } + + this._refresh(); + + if (this.active.length) { + this.load(options.active); + } + }, + + _initialActive: function () { + var active = this.options.active, + collapsible = this.options.collapsible, + locationHash = location.hash.substring(1); + + if (active === null) { + + // check the fragment identifier in the URL + if (locationHash) { + this.tabs.each(function (i, tab) { + if ($(tab).attr("aria-controls") === locationHash) { + active = i; + return false; + } + }); + } + + // Check for a tab marked active via a class + if (active === null) { + active = this.tabs.index(this.tabs.filter(".ui-tabs-active")); + } + + // No active tab, set to false + if (active === null || active === -1) { + active = this.tabs.length ? 0 : false; + } + } + + // Handle numbers: negative, out of range + if (active !== false) { + active = this.tabs.index(this.tabs.eq(active)); + if (active === -1) { + active = collapsible ? false : 0; + } + } + + // Don't allow collapsible: false and active: false + if (!collapsible && active === false && this.anchors.length) { + active = 0; + } + + return active; + }, + + _getCreateEventData: function () { + return { + tab: this.active, + panel: !this.active.length ? $() : this._getPanelForTab(this.active) + }; + }, + + _tabKeydown: function (event) { + var focusedTab = $($.ui.safeActiveElement(this.document[ 0 ])).closest("li"), + selectedIndex = this.tabs.index(focusedTab), + goingForward = true; + + if (this._handlePageNav(event)) { + return; + } + + switch (event.keyCode) { + case $.ui.keyCode.RIGHT: + case $.ui.keyCode.DOWN: + selectedIndex++; + break; + case $.ui.keyCode.UP: + case $.ui.keyCode.LEFT: + goingForward = false; + selectedIndex--; + break; + case $.ui.keyCode.END: + selectedIndex = this.anchors.length - 1; + break; + case $.ui.keyCode.HOME: + selectedIndex = 0; + break; + case $.ui.keyCode.SPACE: + + // Activate only, no collapsing + event.preventDefault(); + clearTimeout(this.activating); + this._activate(selectedIndex); + return; + case $.ui.keyCode.ENTER: + + // Toggle (cancel delayed activation, allow collapsing) + event.preventDefault(); + clearTimeout(this.activating); + + // Determine if we should collapse or activate + this._activate(selectedIndex === this.options.active ? false : selectedIndex); + return; + default: + return; + } + + // Focus the appropriate tab, based on which key was pressed + event.preventDefault(); + clearTimeout(this.activating); + selectedIndex = this._focusNextTab(selectedIndex, goingForward); + + // Navigating with control/command key will prevent automatic activation + if (!event.ctrlKey && !event.metaKey) { + + // Update aria-selected immediately so that AT think the tab is already selected. + // Otherwise AT may confuse the user by stating that they need to activate the tab, + // but the tab will already be activated by the time the announcement finishes. + focusedTab.attr("aria-selected", "false"); + this.tabs.eq(selectedIndex).attr("aria-selected", "true"); + + this.activating = this._delay(function () { + this.option("active", selectedIndex); + }, this.delay); + } + }, + + _panelKeydown: function (event) { + if (this._handlePageNav(event)) { + return; + } + + // Ctrl+up moves focus to the current tab + if (event.ctrlKey && event.keyCode === $.ui.keyCode.UP) { + event.preventDefault(); + this.active.trigger("focus"); + } + }, + + // Alt+page up/down moves focus to the previous/next tab (and activates) + _handlePageNav: function (event) { + if (event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP) { + this._activate(this._focusNextTab(this.options.active - 1, false)); + return true; + } + if (event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN) { + this._activate(this._focusNextTab(this.options.active + 1, true)); + return true; + } + }, + + _findNextTab: function (index, goingForward) { + var lastTabIndex = this.tabs.length - 1; + + function constrain() { + if (index > lastTabIndex) { + index = 0; + } + if (index < 0) { + index = lastTabIndex; + } + return index; + } + + while ($.inArray(constrain(), this.options.disabled) !== -1) { + index = goingForward ? index + 1 : index - 1; + } + + return index; + }, + + _focusNextTab: function (index, goingForward) { + index = this._findNextTab(index, goingForward); + this.tabs.eq(index).trigger("focus"); + return index; + }, + + _setOption: function (key, value) { + if (key === "active") { + + // _activate() will handle invalid values and update this.options + this._activate(value); + return; + } + + this._super(key, value); + + if (key === "collapsible") { + this._toggleClass("ui-tabs-collapsible", null, value); + + // Setting collapsible: false while collapsed; open first panel + if (!value && this.options.active === false) { + this._activate(0); + } + } + + if (key === "event") { + this._setupEvents(value); + } + + if (key === "heightStyle") { + this._setupHeightStyle(value); + } + }, + + _sanitizeSelector: function (hash) { + return hash ? hash.replace(/[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&") : ""; + }, + + refresh: function () { + var options = this.options, + lis = this.tablist.children(":has(a[href])"); + + // Get disabled tabs from class attribute from HTML + // this will get converted to a boolean if needed in _refresh() + options.disabled = $.map(lis.filter(".ui-state-disabled"), function (tab) { + return lis.index(tab); + }); + + this._processTabs(); + + // Was collapsed or no tabs + if (options.active === false || !this.anchors.length) { + options.active = false; + this.active = $(); + + // was active, but active tab is gone + } else if (this.active.length && !$.contains(this.tablist[ 0 ], this.active[ 0 ])) { + + // all remaining tabs are disabled + if (this.tabs.length === options.disabled.length) { + options.active = false; + this.active = $(); + + // activate previous tab + } else { + this._activate(this._findNextTab(Math.max(0, options.active - 1), false)); + } + + // was active, active tab still exists + } else { + + // make sure active index is correct + options.active = this.tabs.index(this.active); + } + + this._refresh(); + }, + + _refresh: function () { + this._setOptionDisabled(this.options.disabled); + this._setupEvents(this.options.event); + this._setupHeightStyle(this.options.heightStyle); + + this.tabs.not(this.active).attr({ + "aria-selected": "false", + "aria-expanded": "false", + tabIndex: -1 + }); + this.panels.not(this._getPanelForTab(this.active)) + .hide() + .attr({ + "aria-hidden": "true" + }); + + // Make sure one tab is in the tab order + if (!this.active.length) { + this.tabs.eq(0).attr("tabIndex", 0); + } else { + this.active + .attr({ + "aria-selected": "true", + "aria-expanded": "true", + tabIndex: 0 + }); + this._addClass(this.active, "ui-tabs-active", "ui-state-active"); + this._getPanelForTab(this.active) + .show() + .attr({ + "aria-hidden": "false" + }); + } + }, + + _processTabs: function () { + var that = this, + prevTabs = this.tabs, + prevAnchors = this.anchors, + prevPanels = this.panels; + + this.tablist = this._getList().attr("role", "tablist"); + this._addClass(this.tablist, "ui-tabs-nav", + "ui-helper-reset ui-helper-clearfix ui-widget-header"); + + // Prevent users from focusing disabled tabs via click + this.tablist + .on("mousedown" + this.eventNamespace, "> li", function (event) { + if ($(this).is(".ui-state-disabled")) { + event.preventDefault(); + } + }) + + // Support: IE <9 + // Preventing the default action in mousedown doesn't prevent IE + // from focusing the element, so if the anchor gets focused, blur. + // We don't have to worry about focusing the previously focused + // element since clicking on a non-focusable element should focus + // the body anyway. + .on("focus" + this.eventNamespace, ".ui-tabs-anchor", function () { + if ($(this).closest("li").is(".ui-state-disabled")) { + this.blur(); + } + }); + + this.tabs = this.tablist.find("> li:has(a[href])") + .attr({ + role: "tab", + tabIndex: -1 + }); + this._addClass(this.tabs, "ui-tabs-tab", "ui-state-default"); + + this.anchors = this.tabs.map(function () { + return $("a", this)[ 0 ]; + }) + .attr({ + role: "presentation", + tabIndex: -1 + }); + this._addClass(this.anchors, "ui-tabs-anchor"); + + this.panels = $(); + + this.anchors.each(function (i, anchor) { + var selector, panel, panelId, + anchorId = $(anchor).uniqueId().attr("id"), + tab = $(anchor).closest("li"), + originalAriaControls = tab.attr("aria-controls"); + + // Inline tab + if (that._isLocal(anchor)) { + selector = anchor.hash; + panelId = selector.substring(1); + panel = that.element.find(that._sanitizeSelector(selector)); + + // remote tab + } else { + + // If the tab doesn't already have aria-controls, + // generate an id by using a throw-away element + panelId = tab.attr("aria-controls") || $({}).uniqueId()[ 0 ].id; + selector = "#" + panelId; + panel = that.element.find(selector); + if (!panel.length) { + panel = that._createPanel(panelId); + panel.insertAfter(that.panels[ i - 1 ] || that.tablist); + } + panel.attr("aria-live", "polite"); + } + + if (panel.length) { + that.panels = that.panels.add(panel); + } + if (originalAriaControls) { + tab.data("ui-tabs-aria-controls", originalAriaControls); + } + tab.attr({ + "aria-controls": panelId, + "aria-labelledby": anchorId + }); + panel.attr("aria-labelledby", anchorId); + }); + + this.panels.attr("role", "tabpanel"); + this._addClass(this.panels, "ui-tabs-panel", "ui-widget-content"); + + // Avoid memory leaks (#10056) + if (prevTabs) { + this._off(prevTabs.not(this.tabs)); + this._off(prevAnchors.not(this.anchors)); + this._off(prevPanels.not(this.panels)); + } + }, + + // Allow overriding how to find the list for rare usage scenarios (#7715) + _getList: function () { + return this.tablist || this.element.find("ol, ul").eq(0); + }, + + _createPanel: function (id) { + return $("
      ") + .attr("id", id) + .data("ui-tabs-destroy", true); + }, + + _setOptionDisabled: function (disabled) { + var currentItem, li, i; + + if ($.isArray(disabled)) { + if (!disabled.length) { + disabled = false; + } else if (disabled.length === this.anchors.length) { + disabled = true; + } + } + + // Disable tabs + for (i = 0; (li = this.tabs[ i ]); i++) { + currentItem = $(li); + if (disabled === true || $.inArray(i, disabled) !== -1) { + currentItem.attr("aria-disabled", "true"); + this._addClass(currentItem, null, "ui-state-disabled"); + } else { + currentItem.removeAttr("aria-disabled"); + this._removeClass(currentItem, null, "ui-state-disabled"); + } + } + + this.options.disabled = disabled; + + this._toggleClass(this.widget(), this.widgetFullName + "-disabled", null, + disabled === true); + }, + + _setupEvents: function (event) { + var events = {}; + if (event) { + $.each(event.split(" "), function (index, eventName) { + events[ eventName ] = "_eventHandler"; + }); + } + + this._off(this.anchors.add(this.tabs).add(this.panels)); + + // Always prevent the default action, even when disabled + this._on(true, this.anchors, { + click: function (event) { + event.preventDefault(); + } + }); + this._on(this.anchors, events); + this._on(this.tabs, {keydown: "_tabKeydown"}); + this._on(this.panels, {keydown: "_panelKeydown"}); + + this._focusable(this.tabs); + this._hoverable(this.tabs); + }, + + _setupHeightStyle: function (heightStyle) { + var maxHeight, + parent = this.element.parent(); + + if (heightStyle === "fill") { + maxHeight = parent.height(); + maxHeight -= this.element.outerHeight() - this.element.height(); + + this.element.siblings(":visible").each(function () { + var elem = $(this), + position = elem.css("position"); + + if (position === "absolute" || position === "fixed") { + return; + } + maxHeight -= elem.outerHeight(true); + }); + + this.element.children().not(this.panels).each(function () { + maxHeight -= $(this).outerHeight(true); + }); + + this.panels.each(function () { + $(this).height(Math.max(0, maxHeight - + $(this).innerHeight() + $(this).height())); + }) + .css("overflow", "auto"); + } else if (heightStyle === "auto") { + maxHeight = 0; + this.panels.each(function () { + maxHeight = Math.max(maxHeight, $(this).height("").height()); + }).height(maxHeight); + } + }, + + _eventHandler: function (event) { + var options = this.options, + active = this.active, + anchor = $(event.currentTarget), + tab = anchor.closest("li"), + clickedIsActive = tab[ 0 ] === active[ 0 ], + collapsing = clickedIsActive && options.collapsible, + toShow = collapsing ? $() : this._getPanelForTab(tab), + toHide = !active.length ? $() : this._getPanelForTab(active), + eventData = { + oldTab: active, + oldPanel: toHide, + newTab: collapsing ? $() : tab, + newPanel: toShow + }; + + event.preventDefault(); + + if (tab.hasClass("ui-state-disabled") || + // tab is already loading + tab.hasClass("ui-tabs-loading") || + // can't switch durning an animation + this.running || + // click on active header, but not collapsible + (clickedIsActive && !options.collapsible) || + // allow canceling activation + (this._trigger("beforeActivate", event, eventData) === false)) { + return; + } + + options.active = collapsing ? false : this.tabs.index(tab); + + this.active = clickedIsActive ? $() : tab; + if (this.xhr) { + this.xhr.abort(); + } + + if (!toHide.length && !toShow.length) { + $.error("jQuery UI Tabs: Mismatching fragment identifier."); + } + + if (toShow.length) { + this.load(this.tabs.index(tab), event); + } + this._toggle(event, eventData); + }, + + // Handles show/hide for selecting tabs + _toggle: function (event, eventData) { + var that = this, + toShow = eventData.newPanel, + toHide = eventData.oldPanel; + + this.running = true; + + function complete() { + that.running = false; + that._trigger("activate", event, eventData); + } + + function show() { + that._addClass(eventData.newTab.closest("li"), "ui-tabs-active", "ui-state-active"); + + if (toShow.length && that.options.show) { + that._show(toShow, that.options.show, complete); + } else { + toShow.show(); + complete(); + } + } + + // Start out by hiding, then showing, then completing + if (toHide.length && this.options.hide) { + this._hide(toHide, this.options.hide, function () { + that._removeClass(eventData.oldTab.closest("li"), + "ui-tabs-active", "ui-state-active"); + show(); + }); + } else { + this._removeClass(eventData.oldTab.closest("li"), + "ui-tabs-active", "ui-state-active"); + toHide.hide(); + show(); + } + + toHide.attr("aria-hidden", "true"); + eventData.oldTab.attr({ + "aria-selected": "false", + "aria-expanded": "false" + }); + + // If we're switching tabs, remove the old tab from the tab order. + // If we're opening from collapsed state, remove the previous tab from the tab order. + // If we're collapsing, then keep the collapsing tab in the tab order. + if (toShow.length && toHide.length) { + eventData.oldTab.attr("tabIndex", -1); + } else if (toShow.length) { + this.tabs.filter(function () { + return $(this).attr("tabIndex") === 0; + }) + .attr("tabIndex", -1); + } + + toShow.attr("aria-hidden", "false"); + eventData.newTab.attr({ + "aria-selected": "true", + "aria-expanded": "true", + tabIndex: 0 + }); + }, + + _activate: function (index) { + var anchor, + active = this._findActive(index); + + // Trying to activate the already active panel + if (active[ 0 ] === this.active[ 0 ]) { + return; + } + + // Trying to collapse, simulate a click on the current active header + if (!active.length) { + active = this.active; + } + + anchor = active.find(".ui-tabs-anchor")[ 0 ]; + this._eventHandler({ + target: anchor, + currentTarget: anchor, + preventDefault: $.noop + }); + }, + + _findActive: function (index) { + return index === false ? $() : this.tabs.eq(index); + }, + + _getIndex: function (index) { + + // meta-function to give users option to provide a href string instead of a numerical index. + if (typeof index === "string") { + index = this.anchors.index(this.anchors.filter("[href$='" + + $.ui.escapeSelector(index) + "']")); + } + + return index; + }, + + _destroy: function () { + if (this.xhr) { + this.xhr.abort(); + } + + this.tablist + .removeAttr("role") + .off(this.eventNamespace); + + this.anchors + .removeAttr("role tabIndex") + .removeUniqueId(); + + this.tabs.add(this.panels).each(function () { + if ($.data(this, "ui-tabs-destroy")) { + $(this).remove(); + } else { + $(this).removeAttr("role tabIndex " + + "aria-live aria-busy aria-selected aria-labelledby aria-hidden aria-expanded"); + } + }); + + this.tabs.each(function () { + var li = $(this), + prev = li.data("ui-tabs-aria-controls"); + if (prev) { + li + .attr("aria-controls", prev) + .removeData("ui-tabs-aria-controls"); + } else { + li.removeAttr("aria-controls"); + } + }); + + this.panels.show(); + + if (this.options.heightStyle !== "content") { + this.panels.css("height", ""); + } + }, + + enable: function (index) { + var disabled = this.options.disabled; + if (disabled === false) { + return; + } + + if (index === undefined) { + disabled = false; + } else { + index = this._getIndex(index); + if ($.isArray(disabled)) { + disabled = $.map(disabled, function (num) { + return num !== index ? num : null; + }); + } else { + disabled = $.map(this.tabs, function (li, num) { + return num !== index ? num : null; + }); + } + } + this._setOptionDisabled(disabled); + }, + + disable: function (index) { + var disabled = this.options.disabled; + if (disabled === true) { + return; + } + + if (index === undefined) { + disabled = true; + } else { + index = this._getIndex(index); + if ($.inArray(index, disabled) !== -1) { + return; + } + if ($.isArray(disabled)) { + disabled = $.merge([index], disabled).sort(); + } else { + disabled = [index]; + } + } + this._setOptionDisabled(disabled); + }, + + load: function (index, event) { + index = this._getIndex(index); + var that = this, + tab = this.tabs.eq(index), + anchor = tab.find(".ui-tabs-anchor"), + panel = this._getPanelForTab(tab), + eventData = { + tab: tab, + panel: panel + }, + complete = function (jqXHR, status) { + if (status === "abort") { + that.panels.stop(false, true); + } + + that._removeClass(tab, "ui-tabs-loading"); + panel.removeAttr("aria-busy"); + + if (jqXHR === that.xhr) { + delete that.xhr; + } + }; + + // Not remote + if (this._isLocal(anchor[ 0 ])) { + return; + } + + this.xhr = $.ajax(this._ajaxSettings(anchor, event, eventData)); + + // Support: jQuery <1.8 + // jQuery <1.8 returns false if the request is canceled in beforeSend, + // but as of 1.8, $.ajax() always returns a jqXHR object. + if (this.xhr && this.xhr.statusText !== "canceled") { + this._addClass(tab, "ui-tabs-loading"); + panel.attr("aria-busy", "true"); + + this.xhr + .done(function (response, status, jqXHR) { + + // support: jQuery <1.8 + // http://bugs.jquery.com/ticket/11778 + setTimeout(function () { + panel.html(response); + that._trigger("load", event, eventData); + + complete(jqXHR, status); + }, 1); + }) + .fail(function (jqXHR, status) { + + // support: jQuery <1.8 + // http://bugs.jquery.com/ticket/11778 + setTimeout(function () { + complete(jqXHR, status); + }, 1); + }); + } + }, + + _ajaxSettings: function (anchor, event, eventData) { + var that = this; + return { + + // Support: IE <11 only + // Strip any hash that exists to prevent errors with the Ajax request + url: anchor.attr("href").replace(/#.*$/, ""), + beforeSend: function (jqXHR, settings) { + return that._trigger("beforeLoad", event, + $.extend({jqXHR: jqXHR, ajaxSettings: settings}, eventData)); + } + }; + }, + + _getPanelForTab: function (tab) { + var id = $(tab).attr("aria-controls"); + return this.element.find(this._sanitizeSelector("#" + id)); + } + }); + +})(jQuery); diff --git a/pivot4j-analytics/src/main/webapp/resources/pivot4j/js/pivot4j.js b/pivot4j-analytics/src/main/webapp/resources/pivot4j/js/pivot4j.js index 20a803d2..50f90375 100644 --- a/pivot4j-analytics/src/main/webapp/resources/pivot4j/js/pivot4j.js +++ b/pivot4j-analytics/src/main/webapp/resources/pivot4j/js/pivot4j.js @@ -1,443 +1,474 @@ if (jQuery.browser.msie) { - if (parseFloat(jQuery.browser.version) < 8) { - jQuery(document).ready(function() { - jQuery(document.body).addClass("ie-compat"); - }); - } + if (parseFloat(jQuery.browser.version) < 8) { + jQuery(document).ready(function () { + jQuery(document.body).addClass("ie-compat"); + }); + } } if (PrimeFaces.widget.BaseTree) { - var proto = PrimeFaces.widget.BaseTree.prototype; - proto._nodeClick = PrimeFaces.widget.BaseTree.prototype.nodeClick; - proto.nodeClick = function(event, nodeContent) { - if (document.selection) { - document.selection.empty(); - } - - if (event.button != 0) { - event.stopPropagation(); - } else { - this._nodeClick(event, nodeContent); - } - }; - - jQuery(document).on("dblclick", "#repository-form .ui-treenode-content", - function(e) { - var openButton = PF("openButton"); - if (openButton.jq.attr("disabled") != "disabled") { - openButton.jq.click(); - } - }); + var proto = PrimeFaces.widget.BaseTree.prototype; + proto._nodeClick = PrimeFaces.widget.BaseTree.prototype.nodeClick; + proto.nodeClick = function (event, nodeContent) { + if (document.selection) { + document.selection.empty(); + } + + if (event.button !== 0) { + event.stopPropagation(); + } else { + this._nodeClick(event, nodeContent); + } + }; + + jQuery(document).on("dblclick", "#repository-form .ui-treenode-content", + function (e) { + var openButton = PF("openButton"); + if (openButton.jq.attr("disabled") !== "disabled") { + openButton.jq.click(); + } + }); } function initNavigatorDroppables() { - jQuery("#target-tree-pane").droppable({ - over : function(e) { - jQuery("#source-tree-pane .ui-droppable").droppable("disable"); - }, - out : function(e) { - jQuery("#source-tree-pane .ui-droppable").droppable("enable"); - } - }); + jQuery("#target-tree-pane").droppable({ + over: function (e) { + jQuery("#source-tree-pane .ui-droppable").droppable("disable"); + }, + out: function (e) { + jQuery("#source-tree-pane .ui-droppable").droppable("enable"); + } + }); } function initializeTabs(tabs) { - var tabView = jQuery("#tab-panel").tabs({ - heightStyleType : "fill", - activate : onTabSelected - }); + var tabView = jQuery("#tab-panel").tabs({ + heightStyleType: "fill", + activate: onTabSelected + }); - var activeId = getActiveViewId(); - var activeIndex = -1; + var activeId = getActiveViewId(); + var activeIndex = -1; - var index = 0; - for ( var id in tabs) { - if (activeId == id) { - activeIndex = index; - } + var index = 0; + for (var id in tabs) { + if (activeId === id) { + createTab(tabs[id]); + activeIndex = index; - createTab(tabs[id]); - index++; - } + } - tabView.tabs("refresh"); + //createTab(tabs[id]); + index++; + } - if (activeIndex > -1) { - tabView.tabs("option", "active", activeIndex); - } + tabView.tabs("refresh"); + + if (activeIndex > -1) { + tabView.tabs("option", "active", 0); + //tabView.tabs("option", "active", activeIndex); + } } function attachClosingViewParam() { - var id = getViewToClose(); + var id = getViewToClose(); - if (id) { - PrimeFaces.addSubmitParam("close-form", { - viewId : id - }); - } + if (id) { + PrimeFaces.addSubmitParam("close-form", { + viewId: id + }); + } } function getViewToClose() { - return jQuery("#tab-panel").data("viewToClose"); + return jQuery("#tab-panel").data("viewToClose"); } function setViewToClose(id) { - jQuery("#tab-panel").data("viewToClose", id); + jQuery("#tab-panel").data("viewToClose", id); } function getActiveViewId() { - return jQuery("#repository-form\\:view-id").val(); + return jQuery("#repository-form\\:view-id").val(); } function setActiveViewId(id) { - jQuery("#repository-form\\:view-id").val(id); + jQuery("#repository-form\\:view-id").val(id); } function getActiveViewIndex() { - var tabView = jQuery("#tab-panel"); - var tabs = tabView.find("li"); - var activeTab = getActiveTab(); + var tabView = jQuery("#tab-panel"); + var tabs = tabView.find("li"); + var activeTab = getActiveTab(); - return tabs.index(activeTab); + return tabs.index(activeTab); } function getActiveTab() { - var tabView = jQuery("#tab-panel"); - var activeTab = tabView.find("li.ui-tabs-active:first"); + var tabView = jQuery("#tab-panel"); + var activeTab = tabView.find("li.ui-tabs-active:first"); - if (activeTab.size() == 0) { - activeTab = undefined; - } + if (activeTab.length === 0) { + activeTab = undefined; + } - return activeTab; + return activeTab; } function getActiveWindow() { - var tabView = jQuery("#tab-panel"); - var selector = tabView.find("li.ui-tabs-active:first a").attr("href"); + var tabView = jQuery("#tab-panel"); + var selector = tabView.find("li.ui-tabs-active:first a").attr("href"); - var query = jQuery(selector).find("iframe"); - if (query.size() == 0) { - return; - } + var query = jQuery(selector).find("iframe"); + if (query.length === 0) { + return; + } - return query.get(0).contentWindow; + return query.get(0).contentWindow; } function addTab(tab) { - createTab(tab); + createTab(tab); - var tabView = jQuery("#tab-panel").tabs("refresh"); + var tabView = jQuery("#tab-panel").tabs("refresh"); - var index = Math.max(0, tabView.find("li").size() - 1); + var index = Math.max(0, tabView.find("li").length - 1); - tabView.tabs("option", "active", index); + tabView.tabs("option", "active", index); - setActiveViewId(tab.id); + setActiveViewId(tab.id); } function createTab(tab) { - var name = tab.name; + var name = tab.name; - if (!tab.path) { - name = "*" + tab.name; - } + if (!tab.path) { + name = "*" + tab.name; + } - var url; + var url; - if (tab.initialized) { - url = "view.xhtml?"; - } else { - url = "catalog.xhtml?"; - } + if (tab.initialized) { + url = "view.xhtml?"; + } else { + url = "catalog.xhtml?"; + } - url += settings.viewParameterName + "=" + tab.id; + url += settings.viewParameterName + "=" + tab.id; - var tabView = jQuery("#tab-panel"); + var tabView = jQuery("#tab-panel"); - var iframe = jQuery(document.createElement("iframe")); - iframe.attr("frameborder", "0").attr("src", url); + var iframe = jQuery(document.createElement("iframe")); + iframe.attr("frameborder", "0").attr("src", url); - var link = jQuery(document.createElement("a")); - link.attr("href", "#view-" + tab.id); - link.text(name); + var link = jQuery(document.createElement("a")); + link.attr("href", "#view-" + tab.id); + link.text(name); - var button = jQuery(document.createElement("span")).addClass("ui-icon") - .addClass("ui-icon-close").on("click", onTabClose); + var button = jQuery(document.createElement("span")).addClass("ui-icon") + .addClass("ui-icon-close").on("click", onTabClose); - var header = jQuery(document.createElement("li")); - header.append(link); - header.append(button); - header.data("id", tab.id); - header.data("name", tab.name); + var header = jQuery(document.createElement("li")); + header.append(link); + header.append(button); + header.data("id", tab.id); + header.data("name", tab.name); - if (tab.path) { - header.data("path", tab.path); - } + if (tab.path) { + header.data("path", tab.path); + } - if (tab.dirty) { - header.data("dirty", tab.dirty); - header.addClass("dirty"); - } + if (tab.dirty) { + header.data("dirty", tab.dirty); + header.addClass("dirty"); + } - var panel = jQuery(document.createElement("div")); - panel.attr("id", "view-" + tab.id); - panel.append(iframe); + var panel = jQuery(document.createElement("div")); + panel.attr("id", "view-" + tab.id); + panel.append(iframe); - tabView.find("ul").append(header); - tabView.append(panel); + tabView.find("ul").append(header); + tabView.append(panel); } function closeActiveTab() { - closeTab(getActiveViewIndex()); + closeTab(getActiveViewIndex()); } function closeTab(index) { - var tabView = jQuery("#tab-panel"); + var tabView = jQuery("#tab-panel"); - tabView.find("ul.ui-tabs-nav li:eq(" + index + ")").remove(); - tabView.find("div.ui-tabs-panel:eq(" + index + ")").remove(); + tabView.find("ul.ui-tabs-nav li:eq(" + index + ")").remove(); + tabView.find("div.ui-tabs-panel:eq(" + index + ")").remove(); - tabView.tabs("refresh"); + tabView.tabs("refresh"); - setViewToClose(null); + setViewToClose(null); } function getTabIndex(id) { - var tabs = jQuery("#tab-panel div.ui-tabs-panel"); - var activeTab = jQuery("#view-" + id); + var tabs = jQuery("#tab-panel div.ui-tabs-panel"); + var activeTab = jQuery("#view-" + id); - return tabs.index(activeTab); + return tabs.index(activeTab); } function enableSave(enable) { - var tab = getActiveTab(); + var tab = getActiveTab(); - if (enable && typeof onReportChanged == "function") { - onReportChanged(); - } + if (enable && typeof onReportChanged === "function") { + onReportChanged(); + } - if (tab) { - tab.data("dirty", enable); + if (tab) { + tab.data("dirty", enable); - if (enable) { - tab.addClass("dirty"); - } else { - tab.removeClass("dirty"); - } - } + if (enable) { + tab.addClass("dirty"); + } else { + tab.removeClass("dirty"); + } + } } function onReportSaved(args) { - PF("newReportDialog").hide(); + PF("newReportDialog").hide(); - var tab = getActiveTab(); + var tab = getActiveTab(); - tab.find("a:first").text(args.name); - tab.data("name", args.name); - tab.data("path", args.path); + tab.find("a:first").text(args.name); + tab.data("name", args.name); + tab.data("path", args.path); - enableSave(false); + enableSave(false); } function selectTab(id) { - var index = getTabIndex(id); + var index = getTabIndex(id); - var tabView = jQuery("#tab-panel"); - tabView.tabs("select", index); + var tabView = jQuery("#tab-panel"); + tabView.tabs("select", index); } function onTabClose(event) { - var tab = jQuery(this).parent(); + var tab = jQuery(this).parent(); - var href = tab.find("a").attr("href"); - var id = href.substring(6); + var href = tab.find("a").attr("href"); + var id = href.substring(6); - setViewToClose(id); + setViewToClose(id); - if (tab.data("dirty")) { - PF('confirmCloseDialog').show(); - } else { - closeReport(id); - } + if (tab.data("dirty")) { + PF('confirmCloseDialog').show(); + } else { + closeReport(id); + } } function onTabSelected(event, ui) { - var iframe = jQuery(ui.newPanel).find("iframe"); + var iframe = jQuery(ui.newPanel).find("iframe"); - if (iframe.size() == 0) { - return; - } + if (iframe.length === 0) { + return; + } - var contentWin = iframe.get(0).contentWindow; + var contentWin = iframe.get(0).contentWindow; - if (contentWin && typeof contentWin.initLayout == "function") { - contentWin.initLayout(); - } + if (contentWin && typeof contentWin.initLayout === "function") { + contentWin.initLayout(); + } - var href = jQuery(ui.newTab).find("a:first").attr("href"); - var id = href.substring(6); + var href = jQuery(ui.newTab).find("a:first").attr("href"); + var id = href.substring(6); - if (getActiveViewId() != id) { - setActiveViewId(id); + if (getActiveViewId() !== id) { + setActiveViewId(id); - onReportSelected([ { - name : "viewId", - value : id - } ]); - } + onReportSelected([{ + name: "viewId", + value: id + }]); + } } function onViewChanged() { - if (parent && parent.enableSave) { - parent.enableSave(true); - } + if (parent && parent.enableSave) { + parent.enableSave(true); + } } function onThemeChanged() { - jQuery("#tab-panel .ui-tabs-panel iframe").each(function(index, elem) { - var pf = elem.contentWindow.PrimeFaces; - if (pf) { - pf.changeTheme(PF('themeSwitcher').value); - } - }); + jQuery("#tab-panel .ui-tabs-panel iframe").each(function (index, elem) { + var pf = elem.contentWindow.PrimeFaces; + if (pf) { + pf.changeTheme(PF('themeSwitcher').value); + } + }); } function onViewResize() { - for ( var name in PrimeFaces.widgets) { - var widget = PF(name); - if (widget.plot) { - widget.plot.replot(); - } - } + for (var name in PrimeFaces.widgets) { + var widget = PF(name); + if (widget.plot) { + widget.plot.replot(); + } + } } function applyThemeToCMEditor(selector) { - if (!selector) { - selector = ".properties-config .CodeMirror"; - } + if (!selector) { + selector = ".properties-config .CodeMirror"; + } - jQuery(selector).addClass( - "ui-state-default ui-inputfield ui-widget ui-corner-all"); + jQuery(selector).addClass( + "ui-state-default ui-inputfield ui-widget ui-corner-all"); } function showWaitDialog() { - var waitDialog = PF("waitDialog"); + var waitDialog = PF("waitDialog"); - if (waitDialog) { - waitDialog.block(); - } + if (waitDialog) { + waitDialog.block(); + } } function hideWaitDialog() { - var waitDialog = PF("waitDialog"); + var waitDialog = PF("waitDialog"); - if (waitDialog) { - waitDialog.unblock(); - } + if (waitDialog) { + waitDialog.unblock(); + } } function completeMdx(editor) { - editor.suggestions = null; - editor.token = null; - - var cursor = editor.instance.getCursor(); - var token = editor.instance.getTokenAt(cursor); - - var isIdentifier = function(string) { - return /^\[[\w$_ ]*\]$/.test(string); - }; - - var isPartialIdentifier = function(string) { - return /^\[[\w$_ ]*\]?$/.test(string); - }; - - var completeIdentifier = function(token) { - // If it is a property, find out what it is a property of. - while (true) { - tokenProperty = editor.instance.getTokenAt({ - line : cursor.line, - ch : tokenProperty.start - }); - - if (tokenProperty.string != ".") { - break; - } - - tokenProperty = editor.instance.getTokenAt({ - line : cursor.line, - ch : tokenProperty.start - }); - - if (!isIdentifier(tokenProperty.string)) { - break; - } - - if (!context) { - var context = []; - } - - context.splice(0, 0, tokenProperty); - } - - var contextString = null; - if (context) { - contextString = ""; - - for (var i = 0; i < context.length; i++) { - var currentContext = context[i]; - - if (i > 0) { - contextString = contextString + "."; - } - - contextString = contextString + currentContext.string; - } - } - - editor.token = token; - editor.search(token.string.substring(1), contextString, cursor.line, - cursor.ch); - }; - - var tokenProperty = token; - var keyword = token.string; - - token.string = token.string.substring(0, (cursor.ch - token.start)); - - if (isPartialIdentifier(token.string)) { - if (!isIdentifier(keyword)) { - token.end = token.start + token.string.length; - } - - completeIdentifier(token); - } else if (keyword == ".") { - var offset = cursor.ch; - - cursor.ch--; - - var context = []; - - while (cursor.ch > 0) { - var previous = editor.instance.getTokenAt(cursor); - - if (isIdentifier(previous.string)) { - context.splice(0, 0, previous.string); - cursor.ch = previous.start; - } else { - break; - } - } - - if (context.length > 0) { - token.start = offset; - token.end = offset; - token.string = ""; - - editor.token = token; - editor.search("", context.join("."), cursor.line, offset); - } - } else { - editor.complete(); - } -} \ No newline at end of file + editor.suggestions = null; + editor.token = null; + + var cursor = editor.instance.getCursor(); + var token = editor.instance.getTokenAt(cursor); + + var isIdentifier = function (string) { + return /^\[[\w$_ ]*\]$/.test(string); + }; + + var isPartialIdentifier = function (string) { + return /^\[[\w$_ ]*\]?$/.test(string); + }; + + var completeIdentifier = function (token) { + // If it is a property, find out what it is a property of. + while (true) { + tokenProperty = editor.instance.getTokenAt({ + line: cursor.line, + ch: tokenProperty.start + }); + + if (tokenProperty.string !== ".") { + break; + } + + tokenProperty = editor.instance.getTokenAt({ + line: cursor.line, + ch: tokenProperty.start + }); + + if (!isIdentifier(tokenProperty.string)) { + break; + } + + if (!context) { + var context = []; + } + + context.splice(0, 0, tokenProperty); + } + + var contextString = null; + if (context) { + contextString = ""; + + for (var i = 0; i < context.length; i++) { + var currentContext = context[i]; + + if (i > 0) { + contextString = contextString + "."; + } + + contextString = contextString + currentContext.string; + } + } + + editor.token = token; + editor.search(token.string.substring(1), contextString, cursor.line, + cursor.ch); + }; + + var tokenProperty = token; + var keyword = token.string; + + token.string = token.string.substring(0, (cursor.ch - token.start)); + + if (isPartialIdentifier(token.string)) { + if (!isIdentifier(keyword)) { + token.end = token.start + token.string.length; + } + + completeIdentifier(token); + } else if (keyword === ".") { + var offset = cursor.ch; + + cursor.ch--; + + var context = []; + + while (cursor.ch > 0) { + var previous = editor.instance.getTokenAt(cursor); + + if (isIdentifier(previous.string)) { + context.splice(0, 0, previous.string); + cursor.ch = previous.start; + } else { + break; + } + } + + if (context.length > 0) { + token.start = offset; + token.end = offset; + token.string = ""; + + editor.token = token; + editor.search("", context.join("."), cursor.line, offset); + } + } else { + editor.complete(); + } +} + +function exportChart() { + var Children = document.getElementsByClassName("jqplot-target"); + var numCharts = Children.length; + var arrAnchors = new Array(); + var jqpoltParentDiv; + var anchorElem; + var imgElem; + var i = 0; + for (i = 0; i < numCharts; i++) { + jqpoltParentDiv = Children[i]; + anchorElem = document.createElement('a'); + imgElem = $(jqpoltParentDiv).jqplotToImageElem(); + $(anchorElem).prop("id", "chart-anchor" + i); + $(anchorElem).prop("download", "chart" + i + ".png"); + $(imgElem).prop("id", "chart-img" + i); + $(anchorElem).prop("href", $(imgElem).prop("src")); + $(anchorElem).append(imgElem); + if (i == 0) + $('#chart-export-form\\:chart-img-div').empty(); + $('#chart-export-form\\:chart-img-div').append(anchorElem); + arrAnchors.push(anchorElem); + } + for (i = 0; i < numCharts; i++) { + anchorElem = arrAnchors[i]; + $(anchorElem)[0].click(); + } +} diff --git a/pivot4j-analytics/src/main/webapp/security/login.xhtml b/pivot4j-analytics/src/main/webapp/security/login.xhtml new file mode 100644 index 00000000..4bc2d7c9 --- /dev/null +++ b/pivot4j-analytics/src/main/webapp/security/login.xhtml @@ -0,0 +1,89 @@ + + + + + + + + + #{msg['title.about.welcome']} + + + + + + + + + +
      +
      +
      +
      +
      + +
      +
      +
      +
      + + +
      +
      + +
      + +
      + + +
      +
      + +
      + +
      + + + + +
      + + + #{msg['security.login.error']}
      + +
      +
      +
      + + + + +
      + + + + + +
      +
      + + + + +
      +
      + +
      + +
      +
      +
      +
      + \ No newline at end of file diff --git a/pivot4j-analytics/src/main/webapp/view.xhtml b/pivot4j-analytics/src/main/webapp/view.xhtml index 5b26eca9..d22fbf78 100644 --- a/pivot4j-analytics/src/main/webapp/view.xhtml +++ b/pivot4j-analytics/src/main/webapp/view.xhtml @@ -1,594 +1,601 @@ - - - - - #{msg['title']} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - initNavigatorDroppables(); - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + #{msg['title']} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + initNavigatorDroppables(); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pivot4j-analytics/src/main/xsl/log4j2-test.xsl b/pivot4j-analytics/src/main/xsl/log4j2-test.xsl index 0d740ed1..2299b279 100644 --- a/pivot4j-analytics/src/main/xsl/log4j2-test.xsl +++ b/pivot4j-analytics/src/main/xsl/log4j2-test.xsl @@ -5,31 +5,31 @@ "> ]> - - - + xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> + + + - - - - - + + + + + - - - - - - - + + + + + + + - - - - - &cr;&tab;&tab;&tab; - &cr;&tab;&tab; - - + + + + + &cr;&tab;&tab;&tab; + &cr;&tab;&tab; + + \ No newline at end of file diff --git a/pivot4j-analytics/src/main/xsl/web.xsl b/pivot4j-analytics/src/main/xsl/web.xsl index b4fd6633..3ff64e24 100644 --- a/pivot4j-analytics/src/main/xsl/web.xsl +++ b/pivot4j-analytics/src/main/xsl/web.xsl @@ -5,23 +5,23 @@ "> ]> - - + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:web-app="http://java.sun.com/xml/ns/javaee"> + + - - - - - + + + + + - - &cr;&tab;&tab; - javax.faces.PROJECT_STAGE&cr;&tab;&tab; - - - &cr;&tab; - - + + &cr;&tab;&tab; + javax.faces.PROJECT_STAGE&cr;&tab;&tab; + + + &cr;&tab; + + \ No newline at end of file diff --git a/pivot4j-analytics/src/test/java/org/pivot4j/analytics/AbstractIntegrationTestCase.java b/pivot4j-analytics/src/test/java/org/pivot4j/analytics/AbstractIntegrationTestCase.java index aa383977..a340f828 100644 --- a/pivot4j-analytics/src/test/java/org/pivot4j/analytics/AbstractIntegrationTestCase.java +++ b/pivot4j-analytics/src/test/java/org/pivot4j/analytics/AbstractIntegrationTestCase.java @@ -40,116 +40,116 @@ @RunWith(Arquillian.class) public abstract class AbstractIntegrationTestCase { - @ArquillianResource - private URL url; - - @Drone - private WebDriver driver; - - @Deployment(testable = false) - public static WebArchive createArtifact() throws TransformerException { - Logger logger = LoggerFactory - .getLogger(AbstractIntegrationTestCase.class); - - TransformerFactory factory = TransformerFactory.newInstance(); - Source template = new StreamSource(new File("src/test/xsl/web.xsl")); - - Transformer transformer = factory.newTransformer(template); - - Source source = new StreamSource(new File( - "src/main/webapp/WEB-INF/web.xml")); - - StringWriter writer = new StringWriter(); - Result out = new StreamResult(writer); - - transformer.transform(source, out); - - WebArchive archive = ShrinkWrap - .create(WebArchive.class, "pivot4j.war") - .merge(ShrinkWrap - .create(GenericArchive.class) - .as(ExplodedImporter.class) - .importDirectory( - "src/main/webapp".replace('/', - File.separatorChar)) - .as(GenericArchive.class), - "/", - Filters.exclude("/WEB-INF/(web|faces-config|pivot4j-config).xml")) - .addPackages( - true, - Filters.exclude(LocalFile.class, - LocalFileSystemRepository.class), - "org.pivot4j.analytics") - .addClasses(TestFile.class, TestRepositoryImpl.class, - TestRepository.class) - .addAsResource( - getFileForPath("src/main/resources/org/pivot4j/analytics/i18n/messages.properties"), - "/org/pivot4j/analytics/i18n/messages.properties") - .addAsWebInfResource(new StringAsset(writer.toString()), - "web.xml") - .addAsWebInfResource( - getFileForPath("src/test/webapp/WEB-INF/faces-config.xml")) - .addAsWebInfResource( - getFileForPath("src/test/resources/pivot4j-config.xml")) - .addAsResource( - getFileForPath("src/main/resources/log4j2-test.xml")) - .addAsResource( - getFileForPath("src/main/resources/mondrian.properties")); - - if (logger.isDebugEnabled()) { - logger.debug("Creating an web archive for testing : " + archive); - logger.debug(archive.toString(true)); - } - - return archive; - } - - /** - * @param path - * @return - */ - private static File getFileForPath(String path) { - return new File(path.replace('/', File.separatorChar)); - } - - public Dimension getWindowSize() { - return new Dimension(1280, 1024); - } - - @Before - public void setUp() { - String address = url.toExternalForm(); - if (!driver.getCurrentUrl().equals(address)) { - configureDriverOptions(driver.manage()); - driver.get(address); - } - } - - /** - * @param options - */ - protected void configureDriverOptions(Options options) { - options.timeouts().setScriptTimeout(30, TimeUnit.SECONDS); - options.timeouts().implicitlyWait(1, TimeUnit.SECONDS); - options.window().setSize(getWindowSize()); - } - - @After - public void tearDown() { - driver.switchTo().defaultContent(); - } - - /** - * @return the url - */ - public URL getUrl() { - return url; - } - - /** - * @return the driver - */ - public WebDriver getDriver() { - return driver; - } + @ArquillianResource + private URL url; + + @Drone + private WebDriver driver; + + @Deployment(testable = false) + public static WebArchive createArtifact() throws TransformerException { + Logger logger = LoggerFactory + .getLogger(AbstractIntegrationTestCase.class); + + TransformerFactory factory = TransformerFactory.newInstance(); + Source template = new StreamSource(new File("src/test/xsl/web.xsl")); + + Transformer transformer = factory.newTransformer(template); + + Source source = new StreamSource(new File( + "src/main/webapp/WEB-INF/web.xml")); + + StringWriter writer = new StringWriter(); + Result out = new StreamResult(writer); + + transformer.transform(source, out); + + WebArchive archive = ShrinkWrap + .create(WebArchive.class, "pivot4j.war") + .merge(ShrinkWrap + .create(GenericArchive.class) + .as(ExplodedImporter.class) + .importDirectory( + "src/main/webapp".replace('/', + File.separatorChar)) + .as(GenericArchive.class), + "/", + Filters.exclude("/WEB-INF/(web|faces-config|pivot4j-config).xml")) + .addPackages( + true, + Filters.exclude(LocalFile.class, + LocalFileSystemRepository.class), + "org.pivot4j.analytics") + .addClasses(TestFile.class, TestRepositoryImpl.class, + TestRepository.class) + .addAsResource( + getFileForPath("src/main/resources/org/pivot4j/analytics/i18n/messages.properties"), + "/org/pivot4j/analytics/i18n/messages.properties") + .addAsWebInfResource(new StringAsset(writer.toString()), + "web.xml") + .addAsWebInfResource( + getFileForPath("src/test/webapp/WEB-INF/faces-config.xml")) + .addAsWebInfResource( + getFileForPath("src/test/resources/pivot4j-config.xml")) + .addAsResource( + getFileForPath("src/main/resources/log4j2-test.xml")) + .addAsResource( + getFileForPath("src/main/resources/mondrian.properties")); + + if (logger.isDebugEnabled()) { + logger.debug("Creating an web archive for testing : " + archive); + logger.debug(archive.toString(true)); + } + + return archive; + } + + /** + * @param path + * @return + */ + private static File getFileForPath(String path) { + return new File(path.replace('/', File.separatorChar)); + } + + public Dimension getWindowSize() { + return new Dimension(1280, 1024); + } + + @Before + public void setUp() { + String address = url.toExternalForm(); + if (!driver.getCurrentUrl().equals(address)) { + configureDriverOptions(driver.manage()); + driver.get(address); + } + } + + /** + * @param options + */ + protected void configureDriverOptions(Options options) { + options.timeouts().setScriptTimeout(30, TimeUnit.SECONDS); + options.timeouts().implicitlyWait(1, TimeUnit.SECONDS); + options.window().setSize(getWindowSize()); + } + + @After + public void tearDown() { + driver.switchTo().defaultContent(); + } + + /** + * @return the url + */ + public URL getUrl() { + return url; + } + + /** + * @return the driver + */ + public WebDriver getDriver() { + return driver; + } } diff --git a/pivot4j-analytics/src/test/java/org/pivot4j/analytics/LayoutIT.java b/pivot4j-analytics/src/test/java/org/pivot4j/analytics/LayoutIT.java index d289d75c..5de6d186 100644 --- a/pivot4j-analytics/src/test/java/org/pivot4j/analytics/LayoutIT.java +++ b/pivot4j-analytics/src/test/java/org/pivot4j/analytics/LayoutIT.java @@ -24,151 +24,151 @@ public class LayoutIT extends AbstractIntegrationTestCase { - @Page - private WorkbenchPage page; - - @Test - public void testPageTitle() { - assertThat("Unexpected page title.", getDriver().getTitle(), - is(equalTo("Pivot4J Sample Application"))); - } - - @Test - public void testToolbar() { - Toolbar toolbar = page.getToolbar(); - - assertThat("Unable to find the application toolbar.", toolbar, - is(notNullValue())); - assertThat("Toolbar pane has wrong height.", 35d, - is(closeTo(toolbar.getSize().height, 5d))); + @Page + private WorkbenchPage page; + + @Test + public void testPageTitle() { + assertThat("Unexpected page title.", getDriver().getTitle(), + is(equalTo("Pivot4J Sample Application"))); + } + + @Test + public void testToolbar() { + Toolbar toolbar = page.getToolbar(); + + assertThat("Unable to find the application toolbar.", toolbar, + is(notNullValue())); + assertThat("Toolbar pane has wrong height.", 35d, + is(closeTo(toolbar.getSize().height, 5d))); - List
      - - - - - - - - - - - - - - - - - - -
      - - - - - - -
      - - - - - - -
      - - - - - -
      - - - - - - - - - -
      -
      - - - - - - - - - - - - - -
      - - - - - - - - - - - - Verkaufen - Ventes - Cube des ventes - Cube Verkaufen - Cube den Verkaufen - -
      - - - - - - - - - - - - - - - - - - - - - - -
      - - - - - - - - - - - - - - -
      - - - - - -
      - - - - - - -"fname" || ' ' || "lname" - - -`customer`.`fullname` - - -"fname" || ' ' || "lname" - - -fname + ' ' + lname - - -"fname" || ' ' || "lname" - - -CONCAT(`customer`.`fname`, ' ', `customer`.`lname`) - - -fname + ' ' + lname - - -"customer"."fullname" - - -CONCAT(CONCAT("customer"."fname", ' '), "customer"."lname") - - -"fname" || ' ' || "lname" - - -"customer"."fullname" - - -"fname" || ' ' || "lname" - - -fullname - - - - -"fname" || ' ' || "lname" - - -"fname" || ' ' || "lname" - - -fname + ' ' + lname - - -"fname" || ' ' || "lname" - - -CONCAT(`customer`.`fname`, ' ', `customer`.`lname`) - - -fname + ' ' + lname - - -"customer"."fullname" - - -"customer"."fullname" - - -CONCAT(CONCAT("customer"."fname", ' '), "customer"."lname") - - -"fname" || ' ' || "lname" - - -fullname - - - - - - - - - - - -
      - - - - - -
      - - - - - -
      - - - - - -
      - - - - - - - - - - - - -Iif("sales_fact_1997"."promotion_id" = 0, 0, "sales_fact_1997"."store_sales") - - -(case when "sales_fact_1997"."promotion_id" = 0 then 0 else "sales_fact_1997"."store_sales" end) - - -(case when "sales_fact_1997"."promotion_id" = 0 then 0 else "sales_fact_1997"."store_sales" end) - - -(case when "sales_fact_1997"."promotion_id" = 0 then 0 else "sales_fact_1997"."store_sales" end) - - -(case when `sales_fact_1997`.`promotion_id` = 0 then 0 else `sales_fact_1997`.`store_sales` end) - - - -(case when "sales_fact_1997"."promotion_id" = 0 then 0 else "sales_fact_1997"."store_sales" end) - - -`sales_fact_1997`.`store_sales` - - -(case when "sales_fact_1997"."promotion_id" = 0 then 0 else "sales_fact_1997"."store_sales" end) - - -(case when "sales_fact_1997"."promotion_id" = 0 then 0 else "sales_fact_1997"."store_sales" end) - - -(case when "sales_fact_1997"."promotion_id" = 0 then 0 else "sales_fact_1997"."store_sales" end) - - -(case when sales_fact_1997.promotion_id = 0 then 0 else sales_fact_1997.store_sales end) - - - - - [Measures].[Store Sales] - [Measures].[Store Cost] - - - - - - - - - - - - - -
      - - - - - - - - - - - - - - - - - -`warehouse_sales` - `inventory_fact_1997`.`warehouse_cost` - - -`warehouse_sales` - `inventory_fact_1997`.`warehouse_cost` - - + + + + + + +
      + + + + + + + + + + + + + + + + + + +
      + + + + + + +
      + + + + + + +
      + + + + + +
      + + + + + + + + + +
      +
      + + + + + + + + + + + + + +
      + + + + + + + + + + + + Verkaufen + Ventes + Cube des ventes + Cube Verkaufen + Cube den Verkaufen + +
      + + + + + + + + + + + + + + + + + + + + + + +
      + + + + + + + + + + + + + + +
      + + + + + +
      + + + + + + + "fname" || ' ' || "lname" + + + `customer`.`fullname` + + + "fname" || ' ' || "lname" + + + fname + ' ' + lname + + + "fname" || ' ' || "lname" + + + CONCAT(`customer`.`fname`, ' ', `customer`.`lname`) + + + fname + ' ' + lname + + + "customer"."fullname" + + + CONCAT(CONCAT("customer"."fname", ' '), "customer"."lname") + + + "fname" || ' ' || "lname" + + + "customer"."fullname" + + + "fname" || ' ' || "lname" + + + fullname + + + + + "fname" || ' ' || "lname" + + + "fname" || ' ' || "lname" + + + fname + ' ' + lname + + + "fname" || ' ' || "lname" + + + CONCAT(`customer`.`fname`, ' ', `customer`.`lname`) + + + fname + ' ' + lname + + + "customer"."fullname" + + + "customer"."fullname" + + + CONCAT(CONCAT("customer"."fname", ' '), "customer"."lname") + + + "fname" || ' ' || "lname" + + + fullname + + + + + + + + + + + +
      + + + + + +
      + + + + + +
      + + + + + +
      + + + + + + + + + + + + + Iif("sales_fact_1997"."promotion_id" = 0, 0, "sales_fact_1997"."store_sales") + + + (case when "sales_fact_1997"."promotion_id" = 0 then 0 else "sales_fact_1997"."store_sales" end) + + + (case when "sales_fact_1997"."promotion_id" = 0 then 0 else "sales_fact_1997"."store_sales" end) + + + (case when "sales_fact_1997"."promotion_id" = 0 then 0 else "sales_fact_1997"."store_sales" end) + + + (case when `sales_fact_1997`.`promotion_id` = 0 then 0 else `sales_fact_1997`.`store_sales` end) + + + + (case when "sales_fact_1997"."promotion_id" = 0 then 0 else "sales_fact_1997"."store_sales" end) + + + `sales_fact_1997`.`store_sales` + + + (case when "sales_fact_1997"."promotion_id" = 0 then 0 else "sales_fact_1997"."store_sales" end) + + + (case when "sales_fact_1997"."promotion_id" = 0 then 0 else "sales_fact_1997"."store_sales" end) + + + (case when "sales_fact_1997"."promotion_id" = 0 then 0 else "sales_fact_1997"."store_sales" end) + + + (case when sales_fact_1997.promotion_id = 0 then 0 else sales_fact_1997.store_sales end) + + + + + [Measures].[Store Sales] - [Measures].[Store Cost] + + + + + + + + + + + + + +
      + + + + + + + + + + + + + + + + + + `warehouse_sales` - `inventory_fact_1997`.`warehouse_cost` + + + `warehouse_sales` - `inventory_fact_1997`.`warehouse_cost` + + "warehouse_sales" - "inventory_fact_1997"."warehouse_cost" - - - - - [Measures].[Warehouse Sales] / [Measures].[Warehouse Cost] - - - - TopCount([Warehouse].[Warehouse Name].MEMBERS, 5, [Measures].[Warehouse Sales]) - - - - - -
      - - - - - - - - - - - - - - - - - - - - - - -
      - - - -
      - - - - - - - - - - -
      + + + + + [Measures].[Warehouse Sales] / [Measures].[Warehouse Cost] + + + + TopCount([Warehouse].[Warehouse Name].MEMBERS, 5, [Measures].[Warehouse Sales]) + + + + +
      - - - - - - - - - - - - - - - - - - - - -
      -
      - - - - - - - - -
      -
      - - - - - - - -
      - - - - - - - -
      - - - - - -
      - - -
      - - - - - - - - - - - - - - - - - - - - -
      - - -
      - - - - - - - - - - - - - - - - - - - - - -
      - - - - - - - - - - - - -
      - - - - - -
      - - - - - -
      - - - - - - -"fname" || ' ' || "lname" - - -"fname" || ' ' || "lname" - - -fname + ' ' + lname - - -"fname" || ' ' || "lname" - - -CONCAT(`customer`.`fname`, ' ', `customer`.`lname`) - - -fname + ' ' + lname - - -"customer"."fullname" - - -CONCAT(CONCAT("customer"."fname", ' '), "customer"."lname") - - -"fname" || ' ' || "lname" - - -"customer"."fullname" - - -fullname - - - - - - - - - - - -
      - - - - - -
      - - - - - -
      - - - - - -
      - - - - - - - - - - - - - - - - - - - - - - - - -
      - - - - - - -
      - - - - - - - - - - - - - - - - - - - - - - - - - - [Measures].[Store Sales] - [Measures].[Store Cost] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - [Measures].[Profit] / [Measures].[Units Shipped] - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + + + + + + +
      +
      + + + + + + + + + + + + + + + + + + + + +
      +
      + + + + + + + + +
      +
      + + + + + + + +
      + + + + + + + +
      + + + + + +
      + + +
      + + + + + + + + + + + + + + + + + + + + +
      + + +
      + + + + + + + + + + + + + + + + + + + + + +
      + + + + + + + + + + + + +
      + + + + + +
      + + + + + +
      + + + + + + + "fname" || ' ' || "lname" + + + "fname" || ' ' || "lname" + + + fname + ' ' + lname + + + "fname" || ' ' || "lname" + + + CONCAT(`customer`.`fname`, ' ', `customer`.`lname`) + + + fname + ' ' + lname + + + "customer"."fullname" + + + CONCAT(CONCAT("customer"."fname", ' '), "customer"."lname") + + + "fname" || ' ' || "lname" + + + "customer"."fullname" + + + fullname + + + + + + + + + + + +
      + + + + + +
      + + + + + +
      + + + + + +
      + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + + + + +
      + + + + + + + + + + + + + + + + + + + + + + + + + + [Measures].[Store Sales] - [Measures].[Store Cost] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [Measures].[Profit] / [Measures].[Units Shipped] + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pivot4j-core/src/test/java/org/pivot4j/AbstractIntegrationTestCase.java b/pivot4j-core/src/test/java/org/pivot4j/AbstractIntegrationTestCase.java index 6a16fd36..38741ddc 100644 --- a/pivot4j-core/src/test/java/org/pivot4j/AbstractIntegrationTestCase.java +++ b/pivot4j-core/src/test/java/org/pivot4j/AbstractIntegrationTestCase.java @@ -32,131 +32,131 @@ public abstract class AbstractIntegrationTestCase { - private OlapDataSource dataSource; - - private PivotModel model; - - @Before - public void setUp() throws Exception { - Class.forName("org.apache.derby.jdbc.ClientDriver"); - - Locale.setDefault(Locale.US); - - this.dataSource = createMondrianDataSource(); - this.model = createPivotModel(dataSource); - } - - @After - public void tearDown() throws Exception { - if (model != null && model.isInitialized()) { - model.destroy(); - - this.model = null; - } - - this.dataSource = null; - } - - protected OlapDataSource createMondrianDataSource() - throws ClassNotFoundException { - Class.forName("mondrian.olap4j.MondrianOlap4jDriver"); - - StringBuilder builder = new StringBuilder(); - builder.append("jdbc:mondrian:"); - builder.append(RolapConnectionProperties.Jdbc.name()); - builder.append("=jdbc:derby://localhost/foodmart;"); - builder.append(";"); - builder.append(RolapConnectionProperties.JdbcDrivers.name()); - builder.append("="); - builder.append(ClientDriver.class.getName()); - builder.append(";"); - builder.append(RolapConnectionProperties.JdbcUser.name()); - builder.append("=sa;"); - - builder.append(RolapConnectionProperties.Catalog.name()); - builder.append("=file:"); - - String basedir = System.getProperty("basedir"); - if (basedir == null) { - basedir = System.getProperty("user.dir"); - } - - builder.append(basedir); - builder.append(File.separator); - builder.append("src"); - builder.append(File.separator); - builder.append("test"); - builder.append(File.separator); - builder.append("config"); - builder.append(File.separator); - builder.append("FoodMart.xml"); - - builder.append(";"); - - String url = builder.toString(); - - SimpleOlapDataSource dataSource = new SimpleOlapDataSource(); - dataSource.setConnectionString(url); - - return dataSource; - } - - protected PivotModel createPivotModel(OlapDataSource dataSource) { - PivotModel model = new PivotModelImpl(dataSource); - model.setLocale(Locale.US); - - return model; - } - - /** - * @return the dataSource - */ - protected OlapDataSource getDataSource() { - return dataSource; - } - - /** - * @return the model - */ - protected PivotModel getPivotModel() { - return model; - } - - /** - * @param name - * @return - * @throws IOException - */ - protected String readTestResource(String name) throws IOException { - StringBuilder builder = new StringBuilder(); - builder.append('/'); - builder.append(getClass().getPackage().getName().replace('.', '/')); - builder.append('/'); - builder.append(name); - - String path = builder.toString(); - - InputStream in = getClass().getResourceAsStream(path); - - if (in == null) { - assertThat("No resource was found with given name : " + path, in, - is(notNullValue())); - } - - BufferedReader reader = new BufferedReader(new InputStreamReader(in)); - - StringWriter writer = new StringWriter(); - - String line = null; - while ((line = reader.readLine()) != null) { - writer.append(line); - writer.append('\n'); - } - - reader.close(); - writer.flush(); - writer.close(); - - return writer.toString().trim(); - } + private OlapDataSource dataSource; + + private PivotModel model; + + @Before + public void setUp() throws Exception { + Class.forName("org.apache.derby.jdbc.ClientDriver"); + + Locale.setDefault(Locale.US); + + this.dataSource = createMondrianDataSource(); + this.model = createPivotModel(dataSource); + } + + @After + public void tearDown() throws Exception { + if (model != null && model.isInitialized()) { + model.destroy(); + + this.model = null; + } + + this.dataSource = null; + } + + protected OlapDataSource createMondrianDataSource() + throws ClassNotFoundException { + Class.forName("mondrian.olap4j.MondrianOlap4jDriver"); + + StringBuilder builder = new StringBuilder(); + builder.append("jdbc:mondrian:"); + builder.append(RolapConnectionProperties.Jdbc.name()); + builder.append("=jdbc:derby://localhost/foodmart;"); + builder.append(";"); + builder.append(RolapConnectionProperties.JdbcDrivers.name()); + builder.append("="); + builder.append(ClientDriver.class.getName()); + builder.append(";"); + builder.append(RolapConnectionProperties.JdbcUser.name()); + builder.append("=sa;"); + + builder.append(RolapConnectionProperties.Catalog.name()); + builder.append("=file:"); + + String basedir = System.getProperty("basedir"); + if (basedir == null) { + basedir = System.getProperty("user.dir"); + } + + builder.append(basedir); + builder.append(File.separator); + builder.append("src"); + builder.append(File.separator); + builder.append("test"); + builder.append(File.separator); + builder.append("config"); + builder.append(File.separator); + builder.append("FoodMart.xml"); + + builder.append(";"); + + String url = builder.toString(); + + SimpleOlapDataSource dataSource = new SimpleOlapDataSource(); + dataSource.setConnectionString(url); + + return dataSource; + } + + protected PivotModel createPivotModel(OlapDataSource dataSource) { + PivotModel model = new PivotModelImpl(dataSource); + model.setLocale(Locale.US); + + return model; + } + + /** + * @return the dataSource + */ + protected OlapDataSource getDataSource() { + return dataSource; + } + + /** + * @return the model + */ + protected PivotModel getPivotModel() { + return model; + } + + /** + * @param name + * @return + * @throws IOException + */ + protected String readTestResource(String name) throws IOException { + StringBuilder builder = new StringBuilder(); + builder.append('/'); + builder.append(getClass().getPackage().getName().replace('.', '/')); + builder.append('/'); + builder.append(name); + + String path = builder.toString(); + + InputStream in = getClass().getResourceAsStream(path); + + if (in == null) { + assertThat("No resource was found with given name : " + path, in, + is(notNullValue())); + } + + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + + StringWriter writer = new StringWriter(); + + String line = null; + while ((line = reader.readLine()) != null) { + writer.append(line); + writer.append('\n'); + } + + reader.close(); + writer.flush(); + writer.close(); + + return writer.toString().trim(); + } } diff --git a/pivot4j-core/src/test/java/org/pivot4j/datasource/PooledOlapDataSourceIT.java b/pivot4j-core/src/test/java/org/pivot4j/datasource/PooledOlapDataSourceIT.java index 5c6ed4e3..86dfed5d 100644 --- a/pivot4j-core/src/test/java/org/pivot4j/datasource/PooledOlapDataSourceIT.java +++ b/pivot4j-core/src/test/java/org/pivot4j/datasource/PooledOlapDataSourceIT.java @@ -23,65 +23,64 @@ public class PooledOlapDataSourceIT extends AbstractIntegrationTestCase { - /** - * Test method for - * {@link org.pivot4j.datasource.AbstractOlapDataSource#getConnection()} - * . - * - * @throws SQLException - */ - @Test - public void testGetConnection() throws SQLException { - GenericObjectPool.Config config = new GenericObjectPool.Config(); - config.maxActive = 3; - config.maxIdle = 3; - - PooledOlapDataSource dataSource = new PooledOlapDataSource( - getDataSource(), config); - OlapConnection con1 = dataSource.getConnection(); - OlapConnection con2 = dataSource.getConnection(); - OlapConnection con3 = dataSource.getConnection(); - - assertThat("Invalid connection returned.", con1.isValid(10), is(true)); - assertThat("Invalid connection returned.", con2.isValid(10), is(true)); - assertThat("Invalid connection returned.", con3.isValid(10), is(true)); - - assertThat("Closed connection returned.", con1.isClosed(), is(false)); - assertThat("Closed connection returned.", con2.isClosed(), is(false)); - assertThat("Closed connection returned.", con3.isClosed(), is(false)); - - assertThat("Should return a new Connection instance.", - con1.unwrap(OlapConnection.class), - not(sameInstance(con2.unwrap(OlapConnection.class)))); - assertThat("Should return a new Connection instance.", - con2.unwrap(OlapConnection.class), - not(sameInstance(con3.unwrap(OlapConnection.class)))); - - con3.close(); - - assertThat("Connection should remain open.", con3.isClosed(), is(false)); - - OlapConnection con4 = dataSource.getConnection(); - assertThat("Should reuse an existing connection.", - con3.unwrap(OlapConnection.class), - sameInstance(con4.unwrap(OlapConnection.class))); - - assertThat("Closed connection returned.", con4.isClosed(), is(false)); - - dataSource.close(); - - con1.close(); - con2.close(); - con4.close(); - - assertThat( - "Connection remains open after data source has been closed.", - con1.isClosed(), is(true)); - assertThat( - "Connection remains open after data source has been closed.", - con2.isClosed(), is(true)); - assertThat( - "Connection remains open after data source has been closed.", - con3.isClosed(), is(true)); - } + /** + * Test method for + * {@link org.pivot4j.datasource.AbstractOlapDataSource#getConnection()} . + * + * @throws SQLException + */ + @Test + public void testGetConnection() throws SQLException { + GenericObjectPool.Config config = new GenericObjectPool.Config(); + config.maxActive = 3; + config.maxIdle = 3; + + PooledOlapDataSource dataSource = new PooledOlapDataSource( + getDataSource(), config); + OlapConnection con1 = dataSource.getConnection(); + OlapConnection con2 = dataSource.getConnection(); + OlapConnection con3 = dataSource.getConnection(); + + assertThat("Invalid connection returned.", con1.isValid(10), is(true)); + assertThat("Invalid connection returned.", con2.isValid(10), is(true)); + assertThat("Invalid connection returned.", con3.isValid(10), is(true)); + + assertThat("Closed connection returned.", con1.isClosed(), is(false)); + assertThat("Closed connection returned.", con2.isClosed(), is(false)); + assertThat("Closed connection returned.", con3.isClosed(), is(false)); + + assertThat("Should return a new Connection instance.", + con1.unwrap(OlapConnection.class), + not(sameInstance(con2.unwrap(OlapConnection.class)))); + assertThat("Should return a new Connection instance.", + con2.unwrap(OlapConnection.class), + not(sameInstance(con3.unwrap(OlapConnection.class)))); + + con3.close(); + + assertThat("Connection should remain open.", con3.isClosed(), is(false)); + + OlapConnection con4 = dataSource.getConnection(); + assertThat("Should reuse an existing connection.", + con3.unwrap(OlapConnection.class), + sameInstance(con4.unwrap(OlapConnection.class))); + + assertThat("Closed connection returned.", con4.isClosed(), is(false)); + + dataSource.close(); + + con1.close(); + con2.close(); + con4.close(); + + assertThat( + "Connection remains open after data source has been closed.", + con1.isClosed(), is(true)); + assertThat( + "Connection remains open after data source has been closed.", + con2.isClosed(), is(true)); + assertThat( + "Connection remains open after data source has been closed.", + con3.isClosed(), is(true)); + } } diff --git a/pivot4j-core/src/test/java/org/pivot4j/el/ExpressionEvaluatorIT.java b/pivot4j-core/src/test/java/org/pivot4j/el/ExpressionEvaluatorIT.java index c0082a0b..3ef372fd 100644 --- a/pivot4j-core/src/test/java/org/pivot4j/el/ExpressionEvaluatorIT.java +++ b/pivot4j-core/src/test/java/org/pivot4j/el/ExpressionEvaluatorIT.java @@ -30,157 +30,157 @@ public class ExpressionEvaluatorIT extends AbstractIntegrationTestCase { - @Test - public void testSimpleExpression() { - String query = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "{([Promotion Media].[All Media], " - + "[Product].[All Products])} ON ROWS FROM [Sales] WHERE $[year]"; + @Test + public void testSimpleExpression() { + String query = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "{([Promotion Media].[All Media], " + + "[Product].[All Products])} ON ROWS FROM [Sales] WHERE $[year]"; - PivotModel model = getPivotModel(); + PivotModel model = getPivotModel(); - model.setMdx(query); - model.initialize(); + model.setMdx(query); + model.initialize(); - model.getExpressionContext().put("year", "[Time].[1997]"); + model.getExpressionContext().put("year", "[Time].[1997]"); - ChangeSlicer transform = model.getTransform(ChangeSlicer.class); + ChangeSlicer transform = model.getTransform(ChangeSlicer.class); - List members = transform.getSlicer(); + List members = transform.getSlicer(); - assertThat("Slicer axis should contain ONE member.", members.size(), - is(1)); - assertThat("Wrong member found on the slicer axis.", members.get(0) - .getUniqueName(), equalTo("[Time].[1997]")); - } + assertThat("Slicer axis should contain ONE member.", members.size(), + is(1)); + assertThat("Wrong member found on the slicer axis.", members.get(0) + .getUniqueName(), equalTo("[Time].[1997]")); + } - @Test - public void testFreeMarkerExpression() { - String query = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "{([Promotion Media].[All Media], " - + "$[cube.dimensions.get(\"Product\").defaultHierarchy.defaultMember.uniqueName]" - + ")} ON ROWS FROM [Sales] WHERE [Time].[1997]"; + @Test + public void testFreeMarkerExpression() { + String query = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "{([Promotion Media].[All Media], " + + "$[cube.dimensions.get(\"Product\").defaultHierarchy.defaultMember.uniqueName]" + + ")} ON ROWS FROM [Sales] WHERE [Time].[1997]"; - PivotModel model = getPivotModel(); + PivotModel model = getPivotModel(); - model.setMdx(query); - model.initialize(); + model.setMdx(query); + model.initialize(); - CellSet cellSet = model.getCellSet(); + CellSet cellSet = model.getCellSet(); - List positions = cellSet.getAxes() - .get(Axis.ROWS.axisOrdinal()).getPositions(); - assertThat("Row axis should contain ONE positions.", positions.size(), - is(1)); + List positions = cellSet.getAxes() + .get(Axis.ROWS.axisOrdinal()).getPositions(); + assertThat("Row axis should contain ONE positions.", positions.size(), + is(1)); - Position position = positions.get(0); + Position position = positions.get(0); - assertThat("Row axis should contain two dimensions.", position - .getMembers().size(), is(2)); - assertThat("Wrong member found on the row axis.", position.getMembers() - .get(1).getUniqueName(), equalTo("[Product].[All Products]")); - } + assertThat("Row axis should contain two dimensions.", position + .getMembers().size(), is(2)); + assertThat("Wrong member found on the row axis.", position.getMembers() + .get(1).getUniqueName(), equalTo("[Product].[All Products]")); + } - @Test - public void testPreserveParameterOnSlicerAfterDrillDown() { - String query = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "{([Promotion Media].[All Media], " - + "[Product].[All Products])} ON ROWS FROM [Sales] WHERE $[year]"; + @Test + public void testPreserveParameterOnSlicerAfterDrillDown() { + String query = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "{([Promotion Media].[All Media], " + + "[Product].[All Products])} ON ROWS FROM [Sales] WHERE $[year]"; - PivotModel model = getPivotModel(); + PivotModel model = getPivotModel(); - model.setMdx(query); - model.initialize(); + model.setMdx(query); + model.initialize(); - model.getExpressionContext().put("year", "[Time].[1997]"); + model.getExpressionContext().put("year", "[Time].[1997]"); - ChangeSlicer slicerTransform = model.getTransform(ChangeSlicer.class); + ChangeSlicer slicerTransform = model.getTransform(ChangeSlicer.class); - List members = slicerTransform.getSlicer(); + List members = slicerTransform.getSlicer(); - assertThat("Slicer axis should contain ONE member.", members.size(), - is(1)); + assertThat("Slicer axis should contain ONE member.", members.size(), + is(1)); - assertThat("Wrong member found on the slicer axis.", members.get(0) - .getUniqueName(), equalTo("[Time].[1997]")); + assertThat("Wrong member found on the slicer axis.", members.get(0) + .getUniqueName(), equalTo("[Time].[1997]")); - Member member = OlapUtils.lookupMember("[Product].[All Products]", - model.getCube()); + Member member = OlapUtils.lookupMember("[Product].[All Products]", + model.getCube()); - DrillExpandMember drillTransform = model - .getTransform(DrillExpandMember.class); - drillTransform.expand(member); + DrillExpandMember drillTransform = model + .getTransform(DrillExpandMember.class); + drillTransform.expand(member); - model.getExpressionContext().put("year", "[Time].[1998]"); - model.getCellSet(); + model.getExpressionContext().put("year", "[Time].[1998]"); + model.getCellSet(); - members = slicerTransform.getSlicer(); + members = slicerTransform.getSlicer(); - assertThat("Wrong member found on the slicer axis.", members.get(0) - .getUniqueName(), equalTo("[Time].[1998]")); - } + assertThat("Wrong member found on the slicer axis.", members.get(0) + .getUniqueName(), equalTo("[Time].[1998]")); + } - @Test - public void testPreserveParameterOnSlicerAfterAddingHierarchy() { - String query = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "[Promotion Media].[All Media] ON ROWS FROM [Sales] WHERE $[year]"; + @Test + public void testPreserveParameterOnSlicerAfterAddingHierarchy() { + String query = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "[Promotion Media].[All Media] ON ROWS FROM [Sales] WHERE $[year]"; - PivotModel model = getPivotModel(); + PivotModel model = getPivotModel(); - model.setMdx(query); - model.initialize(); + model.setMdx(query); + model.initialize(); - model.getExpressionContext().put("year", "[Time].[1997]"); + model.getExpressionContext().put("year", "[Time].[1997]"); - ChangeSlicer slicerTransform = model.getTransform(ChangeSlicer.class); + ChangeSlicer slicerTransform = model.getTransform(ChangeSlicer.class); - List members = slicerTransform.getSlicer(); + List members = slicerTransform.getSlicer(); - assertThat("Slicer axis should contain ONE member.", members.size(), - is(1)); + assertThat("Slicer axis should contain ONE member.", members.size(), + is(1)); - assertThat("Wrong member found on the slicer axis.", members.get(0) - .getUniqueName(), equalTo("[Time].[1997]")); + assertThat("Wrong member found on the slicer axis.", members.get(0) + .getUniqueName(), equalTo("[Time].[1997]")); - PlaceHierarchiesOnAxes hierarchyTransform = model - .getTransform(PlaceHierarchiesOnAxes.class); + PlaceHierarchiesOnAxes hierarchyTransform = model + .getTransform(PlaceHierarchiesOnAxes.class); - Hierarchy hierarchy = model.getCube().getHierarchies().get("Product"); + Hierarchy hierarchy = model.getCube().getHierarchies().get("Product"); - hierarchyTransform.addHierarchy(Axis.ROWS, hierarchy, true, -1); + hierarchyTransform.addHierarchy(Axis.ROWS, hierarchy, true, -1); - model.getExpressionContext().put("year", "[Time].[1998]"); - model.getCellSet(); + model.getExpressionContext().put("year", "[Time].[1998]"); + model.getCellSet(); - members = slicerTransform.getSlicer(); + members = slicerTransform.getSlicer(); - assertThat("Wrong member found on the slicer axis.", members.get(0) - .getUniqueName(), equalTo("[Time].[1998]")); - } + assertThat("Wrong member found on the slicer axis.", members.get(0) + .getUniqueName(), equalTo("[Time].[1998]")); + } - @Test - public void testSimpleValueExpression() throws OlapException { - String query = "WITH MEMBER [Measures].[Calc Cost] AS '[Measures].[Store Cost] * ${ratio}' " - + "SELECT {[Measures].[Calc Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales]"; + @Test + public void testSimpleValueExpression() throws OlapException { + String query = "WITH MEMBER [Measures].[Calc Cost] AS '[Measures].[Store Cost] * ${ratio}' " + + "SELECT {[Measures].[Calc Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales]"; - PivotModel model = getPivotModel(); + PivotModel model = getPivotModel(); - model.setMdx(query); - model.initialize(); + model.setMdx(query); + model.initialize(); - model.getExpressionContext().put("ratio", "1.5"); + model.getExpressionContext().put("ratio", "1.5"); - CellSet cellSet = model.getCellSet(); + CellSet cellSet = model.getCellSet(); - assertThat("Wrong cell value returned(ratio = 1.5).", cellSet - .getCell(0).getFormattedValue(), equalTo("338,440.85")); + assertThat("Wrong cell value returned(ratio = 1.5).", cellSet + .getCell(0).getFormattedValue(), equalTo("338,440.85")); - model.getExpressionContext().put("ratio", "2.5"); - model.refresh(); + model.getExpressionContext().put("ratio", "2.5"); + model.refresh(); - cellSet = model.getCellSet(); + cellSet = model.getCellSet(); - assertThat("Wrong cell value returned(ratio = 2.5).", cellSet - .getCell(0).getFormattedValue(), equalTo("564,068.08")); - } + assertThat("Wrong cell value returned(ratio = 2.5).", cellSet + .getCell(0).getFormattedValue(), equalTo("564,068.08")); + } } diff --git a/pivot4j-core/src/test/java/org/pivot4j/impl/PivotModelImplIT.java b/pivot4j-core/src/test/java/org/pivot4j/impl/PivotModelImplIT.java index 51d8bf29..51f50335 100644 --- a/pivot4j-core/src/test/java/org/pivot4j/impl/PivotModelImplIT.java +++ b/pivot4j-core/src/test/java/org/pivot4j/impl/PivotModelImplIT.java @@ -25,93 +25,93 @@ public class PivotModelImplIT extends AbstractIntegrationTestCase { - private String testQuery = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales] WHERE [Time].[1997]"; + private String testQuery = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales] WHERE [Time].[1997]"; - /** - * @return the testQuery - */ - protected String getTestQuery() { - return testQuery; - } + /** + * @return the testQuery + */ + protected String getTestQuery() { + return testQuery; + } - @Test - public void testInitialize() { - PivotModel model = getPivotModel(); - model.setMdx(getTestQuery()); + @Test + public void testInitialize() { + PivotModel model = getPivotModel(); + model.setMdx(getTestQuery()); - assertThat("Model is already initialized.", model.isInitialized(), - is(false)); + assertThat("Model is already initialized.", model.isInitialized(), + is(false)); - model.initialize(); + model.initialize(); - assertThat("Model is not initialized.", model.isInitialized(), is(true)); - } + assertThat("Model is not initialized.", model.isInitialized(), is(true)); + } - @Test(expected = PivotException.class) - public void testInitializeWithNoInitialMdx() { - PivotModel model = getPivotModel(); - model.initialize(); - } + @Test(expected = PivotException.class) + public void testInitializeWithNoInitialMdx() { + PivotModel model = getPivotModel(); + model.initialize(); + } - @Test - public void testDestroy() { - PivotModel model = getPivotModel(); - model.setMdx(getTestQuery()); - model.initialize(); + @Test + public void testDestroy() { + PivotModel model = getPivotModel(); + model.setMdx(getTestQuery()); + model.initialize(); - assertThat("Model is not initialized.", model.isInitialized(), is(true)); + assertThat("Model is not initialized.", model.isInitialized(), is(true)); - model.destroy(); + model.destroy(); - assertThat("Model is not destroyed.", model.isInitialized(), is(false)); - } + assertThat("Model is not destroyed.", model.isInitialized(), is(false)); + } - @Test - public void testGetCellSet() { - PivotModel model = getPivotModel(); - model.setMdx(getTestQuery()); - model.initialize(); + @Test + public void testGetCellSet() { + PivotModel model = getPivotModel(); + model.setMdx(getTestQuery()); + model.initialize(); - CellSet cellSet = model.getCellSet(); + CellSet cellSet = model.getCellSet(); - assertThat("CellSet is null.", cellSet, is(notNullValue())); + assertThat("CellSet is null.", cellSet, is(notNullValue())); - List axes = cellSet.getAxes(); + List axes = cellSet.getAxes(); - assertThat("CELL axes list is null.", axes, is(notNullValue())); - assertThat("Invalid cell axes size.", axes.size(), is(equalTo(2))); - } + assertThat("CELL axes list is null.", axes, is(notNullValue())); + assertThat("Invalid cell axes size.", axes.size(), is(equalTo(2))); + } - @Test - public void testGetMdx() { - PivotModel model = getPivotModel(); - model.setMdx(getTestQuery()); - model.initialize(); + @Test + public void testGetMdx() { + PivotModel model = getPivotModel(); + model.setMdx(getTestQuery()); + model.initialize(); - assertThat("MDX has been modified unexpectedly.", model.getMdx(), - is(equalTo(getTestQuery()))); - } + assertThat("MDX has been modified unexpectedly.", model.getMdx(), + is(equalTo(getTestQuery()))); + } - @Test - public void testGetCurrentMdx() { - PivotModel model = getPivotModel(); - model.setMdx(getTestQuery()); - model.initialize(); + @Test + public void testGetCurrentMdx() { + PivotModel model = getPivotModel(); + model.setMdx(getTestQuery()); + model.initialize(); - String currentMdx = model.getCurrentMdx(); + String currentMdx = model.getCurrentMdx(); - assertThat("MDX has been modified unexpectedly.", currentMdx, - is(equalTo(getTestQuery()))); - } + assertThat("MDX has been modified unexpectedly.", currentMdx, + is(equalTo(getTestQuery()))); + } - @Test(expected = NotInitializedException.class) - public void testGetCellSetBeforeInitialize() { - PivotModel model = getPivotModel(); + @Test(expected = NotInitializedException.class) + public void testGetCellSetBeforeInitialize() { + PivotModel model = getPivotModel(); - assertThat("Model is already initialized.", model.isInitialized(), - is(false)); + assertThat("Model is already initialized.", model.isInitialized(), + is(false)); - model.getCellSet(); - } + model.getCellSet(); + } } diff --git a/pivot4j-core/src/test/java/org/pivot4j/mdx/MdxParserTest.java b/pivot4j-core/src/test/java/org/pivot4j/mdx/MdxParserTest.java index 77217e51..3d0fab20 100644 --- a/pivot4j-core/src/test/java/org/pivot4j/mdx/MdxParserTest.java +++ b/pivot4j-core/src/test/java/org/pivot4j/mdx/MdxParserTest.java @@ -33,527 +33,527 @@ public class MdxParserTest { - /** - * @param mdxQuery - * @return - * @throws Exception - */ - protected MdxStatement parseQuery(String mdxQuery) throws Exception { - MdxParser parser = new MdxParserImpl(); + /** + * @param mdxQuery + * @return + * @throws Exception + */ + protected MdxStatement parseQuery(String mdxQuery) throws Exception { + MdxParser parser = new MdxParserImpl(); - return parser.parse(mdxQuery); - } + return parser.parse(mdxQuery); + } - @Test - public void testParseEmptyAxis() throws Exception { - String mdx = "SELECT FROM DummyCube"; + @Test + public void testParseEmptyAxis() throws Exception { + String mdx = "SELECT FROM DummyCube"; - MdxStatement query = parseQuery(mdx); + MdxStatement query = parseQuery(mdx); - assertThat("Failed to parse : " + mdx, query, is(notNullValue())); - assertThat("Axes should not be null.", query.getAxes(), - is(notNullValue())); - assertThat("Number of axes should be 0.", query.getAxes().isEmpty(), - is(true)); - } + assertThat("Failed to parse : " + mdx, query, is(notNullValue())); + assertThat("Axes should not be null.", query.getAxes(), + is(notNullValue())); + assertThat("Number of axes should be 0.", query.getAxes().isEmpty(), + is(true)); + } - @Test - public void testGenerateEmptyAxis() throws Exception { - String mdx = "SELECT FROM DummyCube"; + @Test + public void testGenerateEmptyAxis() throws Exception { + String mdx = "SELECT FROM DummyCube"; - MdxStatement query = new MdxStatement(); - query.setCube(new CompoundId("DummyCube")); + MdxStatement query = new MdxStatement(); + query.setCube(new CompoundId("DummyCube")); - assertThat("Unexpected MDX query.", query.toMdx(), is(equalTo(mdx))); - } + assertThat("Unexpected MDX query.", query.toMdx(), is(equalTo(mdx))); + } - @Test - public void testParseSingleAxis() throws Exception { - String mdx = "SELECT [AAA] ON COLUMNS FROM DummyCube"; + @Test + public void testParseSingleAxis() throws Exception { + String mdx = "SELECT [AAA] ON COLUMNS FROM DummyCube"; - MdxStatement query = parseQuery(mdx); + MdxStatement query = parseQuery(mdx); - assertThat("Failed to parse : " + mdx, query, is(notNullValue())); - assertThat("Axes should not be null.", query.getAxes(), - is(notNullValue())); + assertThat("Failed to parse : " + mdx, query, is(notNullValue())); + assertThat("Axes should not be null.", query.getAxes(), + is(notNullValue())); - assertThat("Number of axes should be 1.", query.getAxes().size(), - is(equalTo(1))); + assertThat("Number of axes should be 1.", query.getAxes().size(), + is(equalTo(1))); - Exp columnExp = query.getAxes().get(0).getExp(); + Exp columnExp = query.getAxes().get(0).getExp(); - assertThat("Exp object for columns axis is null.", columnExp, - is(notNullValue())); + assertThat("Exp object for columns axis is null.", columnExp, + is(notNullValue())); - assertThat("Exp object should be instance of CompoundId.", columnExp, - is(instanceOf(CompoundId.class))); + assertThat("Exp object should be instance of CompoundId.", columnExp, + is(instanceOf(CompoundId.class))); - mdx = "SELECT [AAA] ON ROWS FROM DummyCube"; + mdx = "SELECT [AAA] ON ROWS FROM DummyCube"; - Exp rowExp = query.getAxes().get(0).getExp(); + Exp rowExp = query.getAxes().get(0).getExp(); - assertThat("Exp object for rows axis is null.", rowExp, - is(notNullValue())); + assertThat("Exp object for rows axis is null.", rowExp, + is(notNullValue())); - assertThat("Exp object should be instance of CompoundId.", rowExp, - is(instanceOf(CompoundId.class))); - } + assertThat("Exp object should be instance of CompoundId.", rowExp, + is(instanceOf(CompoundId.class))); + } - @Test - public void testGenerateSingleAxis() throws Exception { - String mdx = "SELECT [AAA] ON COLUMNS FROM [DummyCube]"; + @Test + public void testGenerateSingleAxis() throws Exception { + String mdx = "SELECT [AAA] ON COLUMNS FROM [DummyCube]"; - MdxStatement query = new MdxStatement(); + MdxStatement query = new MdxStatement(); - QueryAxis axis = new QueryAxis(Axis.COLUMNS, new CompoundId("[AAA]")); - query.setAxis(axis); - query.setCube(new CompoundId("[DummyCube]")); + QueryAxis axis = new QueryAxis(Axis.COLUMNS, new CompoundId("[AAA]")); + query.setAxis(axis); + query.setCube(new CompoundId("[DummyCube]")); - assertThat("Unexpected MDX query.", query.toMdx(), is(equalTo(mdx))); - } + assertThat("Unexpected MDX query.", query.toMdx(), is(equalTo(mdx))); + } - @Test - public void testParseKeyIdentifier() throws Exception { - String mdx = "SELECT [AAA].&[BBB] ON COLUMNS, [CCC].&[DDD]&[EEE] ON ROWS FROM DummyCube"; + @Test + public void testParseKeyIdentifier() throws Exception { + String mdx = "SELECT [AAA].&[BBB] ON COLUMNS, [CCC].&[DDD]&[EEE] ON ROWS FROM DummyCube"; - MdxStatement query = parseQuery(mdx); + MdxStatement query = parseQuery(mdx); - assertThat("Failed to parse : " + mdx, query, is(notNullValue())); - assertThat("Axes should not be null.", query.getAxes(), - is(notNullValue())); + assertThat("Failed to parse : " + mdx, query, is(notNullValue())); + assertThat("Axes should not be null.", query.getAxes(), + is(notNullValue())); - assertThat("Number of axes should be 2.", query.getAxes().size(), - is(equalTo(2))); + assertThat("Number of axes should be 2.", query.getAxes().size(), + is(equalTo(2))); - Exp columnExp = query.getAxes().get(0).getExp(); + Exp columnExp = query.getAxes().get(0).getExp(); - assertThat("Exp object for columns axis is null.", columnExp, - is(notNullValue())); + assertThat("Exp object for columns axis is null.", columnExp, + is(notNullValue())); - assertThat("Exp object should be instance of CompoundId.", columnExp, - is(instanceOf(CompoundId.class))); + assertThat("Exp object should be instance of CompoundId.", columnExp, + is(instanceOf(CompoundId.class))); - CompoundId columnId = (CompoundId) columnExp; - assertThat("Wrong number of name parts on column axis member.", - columnId.getNames().size(), is(equalTo(2))); + CompoundId columnId = (CompoundId) columnExp; + assertThat("Wrong number of name parts on column axis member.", + columnId.getNames().size(), is(equalTo(2))); - assertThat("First name part has wrong identifier.", columnId.getNames() - .get(0).getName(), is(equalTo("[AAA]"))); - assertThat("Second name part has wrong identifier.", columnId - .getNames().get(1).getName(), is(equalTo("[BBB]"))); - assertThat("First name part cannot be a key identifier.", columnId - .getNames().get(0).isKey(), is(false)); - assertThat("Second name part is a key identifier.", columnId.getNames() - .get(1).isKey(), is(true)); + assertThat("First name part has wrong identifier.", columnId.getNames() + .get(0).getName(), is(equalTo("[AAA]"))); + assertThat("Second name part has wrong identifier.", columnId + .getNames().get(1).getName(), is(equalTo("[BBB]"))); + assertThat("First name part cannot be a key identifier.", columnId + .getNames().get(0).isKey(), is(false)); + assertThat("Second name part is a key identifier.", columnId.getNames() + .get(1).isKey(), is(true)); - Exp rowExp = query.getAxes().get(1).getExp(); + Exp rowExp = query.getAxes().get(1).getExp(); - assertThat("Exp object for rows axis is null.", rowExp, - is(notNullValue())); + assertThat("Exp object for rows axis is null.", rowExp, + is(notNullValue())); - assertThat("Exp object should be instance of CompoundId.", rowExp, - is(instanceOf(CompoundId.class))); + assertThat("Exp object should be instance of CompoundId.", rowExp, + is(instanceOf(CompoundId.class))); - CompoundId rowId = (CompoundId) rowExp; - assertThat("Wrong number of name parts on row axis member.", rowId - .getNames().size(), is(equalTo(2))); + CompoundId rowId = (CompoundId) rowExp; + assertThat("Wrong number of name parts on row axis member.", rowId + .getNames().size(), is(equalTo(2))); - assertThat("First name part has wrong identifier.", rowId.getNames() - .get(0).getName(), is(equalTo("[CCC]"))); - assertThat("Second name part has wrong identifier.", rowId.getNames() - .get(1).getName(), is(equalTo("[DDD]&[EEE]"))); - assertThat("First name part cannot be a key identifier.", rowId - .getNames().get(0).isKey(), is(false)); - assertThat("Second name part is a key identifier.", rowId.getNames() - .get(1).isKey(), is(true)); - } + assertThat("First name part has wrong identifier.", rowId.getNames() + .get(0).getName(), is(equalTo("[CCC]"))); + assertThat("Second name part has wrong identifier.", rowId.getNames() + .get(1).getName(), is(equalTo("[DDD]&[EEE]"))); + assertThat("First name part cannot be a key identifier.", rowId + .getNames().get(0).isKey(), is(false)); + assertThat("Second name part is a key identifier.", rowId.getNames() + .get(1).isKey(), is(true)); + } - @Test - public void testGenerateKeyIdentifier() throws Exception { - String mdx = "SELECT [AAA].&[BBB] ON COLUMNS, [CCC].&[DDD]&[EEE] ON ROWS FROM DummyCube"; + @Test + public void testGenerateKeyIdentifier() throws Exception { + String mdx = "SELECT [AAA].&[BBB] ON COLUMNS, [CCC].&[DDD]&[EEE] ON ROWS FROM DummyCube"; - MdxStatement query = new MdxStatement(); + MdxStatement query = new MdxStatement(); - CompoundId columnId = new CompoundId().append("[AAA]").append("[BBB]", - true); - CompoundId rowId = new CompoundId().append("[CCC]").append( - "[DDD]&[EEE]", true); + CompoundId columnId = new CompoundId().append("[AAA]").append("[BBB]", + true); + CompoundId rowId = new CompoundId().append("[CCC]").append( + "[DDD]&[EEE]", true); - query.setAxis(new QueryAxis(Axis.COLUMNS, columnId)); - query.setAxis(new QueryAxis(Axis.ROWS, rowId)); + query.setAxis(new QueryAxis(Axis.COLUMNS, columnId)); + query.setAxis(new QueryAxis(Axis.ROWS, rowId)); - query.setCube(new CompoundId("DummyCube")); + query.setCube(new CompoundId("DummyCube")); - assertThat("Unexpected MDX query.", query.toMdx(), is(equalTo(mdx))); - } + assertThat("Unexpected MDX query.", query.toMdx(), is(equalTo(mdx))); + } - @Test - public void testParseSapVariables() throws Exception { - String mdx = "SELECT [Measures].members ON COLUMNS, NON EMPTY [ODB_CUST].members ON ROWS " - + "FROM [ODBOSCEN1/MKTBRANCH] SAP VARIABLES [ODBBRANC] INCLUDING [ODB_BRANC].[CHEM]"; + @Test + public void testParseSapVariables() throws Exception { + String mdx = "SELECT [Measures].members ON COLUMNS, NON EMPTY [ODB_CUST].members ON ROWS " + + "FROM [ODBOSCEN1/MKTBRANCH] SAP VARIABLES [ODBBRANC] INCLUDING [ODB_BRANC].[CHEM]"; - MdxStatement query = parseQuery(mdx); + MdxStatement query = parseQuery(mdx); - assertThat("Failed to parse : " + mdx, query, is(notNullValue())); - assertThat("SAP varaible list should not be null.", - query.getSapVariables(), is(notNullValue())); + assertThat("Failed to parse : " + mdx, query, is(notNullValue())); + assertThat("SAP varaible list should not be null.", + query.getSapVariables(), is(notNullValue())); - assertThat("Number of SAP variables should be 1.", query - .getSapVariables().size(), is(equalTo(1))); + assertThat("Number of SAP variables should be 1.", query + .getSapVariables().size(), is(equalTo(1))); - SapVariable variable = query.getSapVariables().get(0); + SapVariable variable = query.getSapVariables().get(0); - assertThat("SAP varaible should not be null.", variable, - is(notNullValue())); + assertThat("SAP varaible should not be null.", variable, + is(notNullValue())); - CompoundId name = variable.getName(); - assertThat("Name of the SAP varaible should not be null.", name, - is(notNullValue())); + CompoundId name = variable.getName(); + assertThat("Name of the SAP varaible should not be null.", name, + is(notNullValue())); - List values = variable.getValues(); - assertThat("VALUE list of the SAP varaible should not be null.", - values, is(notNullValue())); - assertThat("Number of the SAP variable value should be 1.", - values.size(), is(equalTo(1))); + List values = variable.getValues(); + assertThat("VALUE list of the SAP varaible should not be null.", + values, is(notNullValue())); + assertThat("Number of the SAP variable value should be 1.", + values.size(), is(equalTo(1))); - SapVariable.Value value = values.get(0); - assertThat("The SAP variable is not an interval value.", - value.isInterval(), is(false)); - assertThat("The SAP variable has specified INCLUDING option.", - value.isIncluding(), is(true)); + SapVariable.Value value = values.get(0); + assertThat("The SAP variable is not an interval value.", + value.isInterval(), is(false)); + assertThat("The SAP variable has specified INCLUDING option.", + value.isIncluding(), is(true)); - assertThat("Option value of the SAP varaible should not be null.", - value.getValue(), is(notNullValue())); + assertThat("Option value of the SAP varaible should not be null.", + value.getValue(), is(notNullValue())); - assertThat( - "Option value of the SAP variable should be instance of CompoundId.", - value.getValue(), is(instanceOf(CompoundId.class))); + assertThat( + "Option value of the SAP variable should be instance of CompoundId.", + value.getValue(), is(instanceOf(CompoundId.class))); - assertThat("Incorrect option value of the SAP variable.", value - .getValue().toMdx(), is(equalTo("[ODB_BRANC].[CHEM]"))); - } + assertThat("Incorrect option value of the SAP variable.", value + .getValue().toMdx(), is(equalTo("[ODB_BRANC].[CHEM]"))); + } - @Test - public void testParseOpeningBracket() throws Exception { - String mdx = "SELECT [AA[BB].[CC] ON COLUMNS, [DD].[[AAB] ON ROWS FROM DummyCube"; + @Test + public void testParseOpeningBracket() throws Exception { + String mdx = "SELECT [AA[BB].[CC] ON COLUMNS, [DD].[[AAB] ON ROWS FROM DummyCube"; - MdxStatement query = parseQuery(mdx); + MdxStatement query = parseQuery(mdx); - assertThat("Failed to parse : " + mdx, query, is(notNullValue())); - assertThat("Axes should not be null.", query.getAxes(), - is(notNullValue())); + assertThat("Failed to parse : " + mdx, query, is(notNullValue())); + assertThat("Axes should not be null.", query.getAxes(), + is(notNullValue())); - assertThat("Number of axes should be 2.", query.getAxes().size(), - is(equalTo(2))); + assertThat("Number of axes should be 2.", query.getAxes().size(), + is(equalTo(2))); - Exp columnExp = query.getAxes().get(0).getExp(); + Exp columnExp = query.getAxes().get(0).getExp(); - assertThat("Exp object for columns axis is null.", columnExp, - is(notNullValue())); + assertThat("Exp object for columns axis is null.", columnExp, + is(notNullValue())); - assertThat("Exp object should be instance of CompoundId.", columnExp, - is(instanceOf(CompoundId.class))); + assertThat("Exp object should be instance of CompoundId.", columnExp, + is(instanceOf(CompoundId.class))); - CompoundId columnMember = (CompoundId) columnExp; - String[] columnNames = columnMember.toStringArray(); + CompoundId columnMember = (CompoundId) columnExp; + String[] columnNames = columnMember.toStringArray(); - assertThat("Segments of column member id is null.", columnNames, - is(notNullValue())); - assertThat("Column member id should contain 2 segment parts.", - columnNames.length, is(equalTo(2))); - assertThat("First segment of the column member element is incorrect.", - columnNames[0], is(equalTo("[AA[BB]"))); - assertThat("Second segment of the column member element is incorrect.", - columnNames[1], is(equalTo("[CC]"))); + assertThat("Segments of column member id is null.", columnNames, + is(notNullValue())); + assertThat("Column member id should contain 2 segment parts.", + columnNames.length, is(equalTo(2))); + assertThat("First segment of the column member element is incorrect.", + columnNames[0], is(equalTo("[AA[BB]"))); + assertThat("Second segment of the column member element is incorrect.", + columnNames[1], is(equalTo("[CC]"))); - Exp rowExp = query.getAxes().get(1).getExp(); + Exp rowExp = query.getAxes().get(1).getExp(); - assertThat("Exp object for rows axis is null.", rowExp, - is(notNullValue())); + assertThat("Exp object for rows axis is null.", rowExp, + is(notNullValue())); - assertThat("Exp object should be instance of CompoundId.", rowExp, - is(instanceOf(CompoundId.class))); + assertThat("Exp object should be instance of CompoundId.", rowExp, + is(instanceOf(CompoundId.class))); - CompoundId rowMember = (CompoundId) rowExp; - String[] rowNames = rowMember.toStringArray(); + CompoundId rowMember = (CompoundId) rowExp; + String[] rowNames = rowMember.toStringArray(); - assertThat("Segments of row member id is null.", rowNames, - is(notNullValue())); - assertThat("Row member id should contain 2 segment parts.", - rowNames.length, is(equalTo(2))); - assertThat("First segment of the row member element is incorrect.", - rowNames[0], is(equalTo("[DD]"))); - assertThat("Second segment of the row member element is incorrect.", - rowNames[1], is(equalTo("[[AAB]"))); - } + assertThat("Segments of row member id is null.", rowNames, + is(notNullValue())); + assertThat("Row member id should contain 2 segment parts.", + rowNames.length, is(equalTo(2))); + assertThat("First segment of the row member element is incorrect.", + rowNames[0], is(equalTo("[DD]"))); + assertThat("Second segment of the row member element is incorrect.", + rowNames[1], is(equalTo("[[AAB]"))); + } - @Test - public void testParseBracketEscape() throws Exception { - String mdx = "SELECT [AA[BB]]].[CC] ON COLUMNS, [DD].[AA]]B] ON ROWS FROM DummyCube"; + @Test + public void testParseBracketEscape() throws Exception { + String mdx = "SELECT [AA[BB]]].[CC] ON COLUMNS, [DD].[AA]]B] ON ROWS FROM DummyCube"; - MdxStatement query = parseQuery(mdx); + MdxStatement query = parseQuery(mdx); - assertThat("Failed to parse : " + mdx, query, is(notNullValue())); - assertThat("Axes should not be null.", query.getAxes(), - is(notNullValue())); + assertThat("Failed to parse : " + mdx, query, is(notNullValue())); + assertThat("Axes should not be null.", query.getAxes(), + is(notNullValue())); - assertThat("Number of axes should be 2.", query.getAxes().size(), - is(equalTo(2))); + assertThat("Number of axes should be 2.", query.getAxes().size(), + is(equalTo(2))); - Exp columnExp = query.getAxes().get(0).getExp(); + Exp columnExp = query.getAxes().get(0).getExp(); - assertThat("Exp object for columns axis is null.", columnExp, - is(notNullValue())); + assertThat("Exp object for columns axis is null.", columnExp, + is(notNullValue())); - assertThat("Exp object should be instance of CompoundId.", columnExp, - is(instanceOf(CompoundId.class))); + assertThat("Exp object should be instance of CompoundId.", columnExp, + is(instanceOf(CompoundId.class))); - CompoundId columnMember = (CompoundId) columnExp; - String[] columnNames = columnMember.toStringArray(); + CompoundId columnMember = (CompoundId) columnExp; + String[] columnNames = columnMember.toStringArray(); - assertThat("Segments of column member id is null.", columnNames, - is(notNullValue())); - assertThat("Column member id should contain 2 segment parts.", - columnNames.length, is(equalTo(2))); - assertThat("First segment of the column member element is incorrect.", - columnNames[0], is(equalTo("[AA[BB]]]"))); - assertThat("Second segment of the column member element is incorrect.", - columnNames[1], is(equalTo("[CC]"))); + assertThat("Segments of column member id is null.", columnNames, + is(notNullValue())); + assertThat("Column member id should contain 2 segment parts.", + columnNames.length, is(equalTo(2))); + assertThat("First segment of the column member element is incorrect.", + columnNames[0], is(equalTo("[AA[BB]]]"))); + assertThat("Second segment of the column member element is incorrect.", + columnNames[1], is(equalTo("[CC]"))); - Exp rowExp = query.getAxes().get(1).getExp(); + Exp rowExp = query.getAxes().get(1).getExp(); - assertThat("Exp object for rows axis is null.", rowExp, - is(notNullValue())); + assertThat("Exp object for rows axis is null.", rowExp, + is(notNullValue())); - assertThat("Exp object should be instance of CompoundId.", rowExp, - is(instanceOf(CompoundId.class))); + assertThat("Exp object should be instance of CompoundId.", rowExp, + is(instanceOf(CompoundId.class))); - CompoundId rowMember = (CompoundId) rowExp; - String[] rowNames = rowMember.toStringArray(); + CompoundId rowMember = (CompoundId) rowExp; + String[] rowNames = rowMember.toStringArray(); - assertThat("Segments of row member id is null.", rowNames, - is(notNullValue())); - assertThat("Row member id should contain 2 segment parts.", - rowNames.length, is(equalTo(2))); - assertThat("First segment of the row member element is incorrect.", - rowNames[0], is(equalTo("[DD]"))); - assertThat("Second segment of the row member element is incorrect.", - rowNames[1], is(equalTo("[AA]]B]"))); - } + assertThat("Segments of row member id is null.", rowNames, + is(notNullValue())); + assertThat("Row member id should contain 2 segment parts.", + rowNames.length, is(equalTo(2))); + assertThat("First segment of the row member element is incorrect.", + rowNames[0], is(equalTo("[DD]"))); + assertThat("Second segment of the row member element is incorrect.", + rowNames[1], is(equalTo("[AA]]B]"))); + } - @Test - public void testGenerateBracketEscape() throws Exception { - String mdx = "SELECT [AA[BB]]].[CC] ON COLUMNS, [DD].[AA]]B] ON ROWS FROM DummyCube"; + @Test + public void testGenerateBracketEscape() throws Exception { + String mdx = "SELECT [AA[BB]]].[CC] ON COLUMNS, [DD].[AA]]B] ON ROWS FROM DummyCube"; - MdxStatement query = new MdxStatement(); + MdxStatement query = new MdxStatement(); - CompoundId columnId = new CompoundId().append("[AA[BB]]]").append( - "[CC]"); - CompoundId rowId = new CompoundId().append("[DD]").append("[AA]]B]"); + CompoundId columnId = new CompoundId().append("[AA[BB]]]").append( + "[CC]"); + CompoundId rowId = new CompoundId().append("[DD]").append("[AA]]B]"); - query.setAxis(new QueryAxis(Axis.COLUMNS, columnId)); - query.setAxis(new QueryAxis(Axis.ROWS, rowId)); + query.setAxis(new QueryAxis(Axis.COLUMNS, columnId)); + query.setAxis(new QueryAxis(Axis.ROWS, rowId)); - query.setCube(new CompoundId("DummyCube")); + query.setCube(new CompoundId("DummyCube")); - assertThat("Unexpected MDX query.", query.toMdx(), is(equalTo(mdx))); - } + assertThat("Unexpected MDX query.", query.toMdx(), is(equalTo(mdx))); + } - @Test - public void testParseWithMember() throws Exception { - String mdx = "WITH MEMBER [Measures].[Special Discount] AS [Measures].[Discount Amount] * 1.5 " - + "MEMBER [Measures].[Premium Discount] AS [Measures].[Discount Amount] * 2.0 " - + "SELECT [Measures].[Special Discount] on COLUMNS, NON EMPTY [Product].[Product].MEMBERS ON ROWS " - + "FROM [Adventure Works] WHERE [Product].[Category].[Bikes]"; + @Test + public void testParseWithMember() throws Exception { + String mdx = "WITH MEMBER [Measures].[Special Discount] AS [Measures].[Discount Amount] * 1.5 " + + "MEMBER [Measures].[Premium Discount] AS [Measures].[Discount Amount] * 2.0 " + + "SELECT [Measures].[Special Discount] on COLUMNS, NON EMPTY [Product].[Product].MEMBERS ON ROWS " + + "FROM [Adventure Works] WHERE [Product].[Category].[Bikes]"; - MdxStatement query = parseQuery(mdx); - assertThat("Failed to parse : " + mdx, query, is(notNullValue())); + MdxStatement query = parseQuery(mdx); + assertThat("Failed to parse : " + mdx, query, is(notNullValue())); - List formulas = query.getFormulas(); + List formulas = query.getFormulas(); - assertThat("Formula list not be null.", formulas, is(notNullValue())); - assertThat("Number of formula should be 2.", formulas.size(), - is(equalTo(2))); + assertThat("Formula list not be null.", formulas, is(notNullValue())); + assertThat("Number of formula should be 2.", formulas.size(), + is(equalTo(2))); - Formula formula = formulas.get(0); + Formula formula = formulas.get(0); - assertThat("Wrong formula type.", formula.getType(), - is(equalTo(Formula.Type.MEMBER))); - assertThat("Wrong calculated member name.", formula.getName().toMdx(), - is(equalTo("[Measures].[Special Discount]"))); + assertThat("Wrong formula type.", formula.getType(), + is(equalTo(Formula.Type.MEMBER))); + assertThat("Wrong calculated member name.", formula.getName().toMdx(), + is(equalTo("[Measures].[Special Discount]"))); - formula = formulas.get(1); + formula = formulas.get(1); - Exp arg = formula.getExp(); + Exp arg = formula.getExp(); - assertThat("Wrong argument type.", arg, is(instanceOf(FunCall.class))); + assertThat("Wrong argument type.", arg, is(instanceOf(FunCall.class))); - FunCall func = (FunCall) arg; + FunCall func = (FunCall) arg; - assertThat("Wrong function type.", func.getType(), - is(equalTo(Syntax.Infix))); - assertThat("Wrong number of function arguments.", - func.getArgs().size(), is(equalTo(2))); - } + assertThat("Wrong function type.", func.getType(), + is(equalTo(Syntax.Infix))); + assertThat("Wrong number of function arguments.", + func.getArgs().size(), is(equalTo(2))); + } - @Test - public void testParseMemberExpression() throws Exception { - String mdx = "SELECT [Measures].[Store Sales] ON COLUMNS, [Product].[All Products] ON ROWS FROM [Sales] " - + "WHERE $[parameter]"; + @Test + public void testParseMemberExpression() throws Exception { + String mdx = "SELECT [Measures].[Store Sales] ON COLUMNS, [Product].[All Products] ON ROWS FROM [Sales] " + + "WHERE $[parameter]"; - MdxStatement query = parseQuery(mdx); - assertThat("Failed to parse : " + mdx, query, is(notNullValue())); + MdxStatement query = parseQuery(mdx); + assertThat("Failed to parse : " + mdx, query, is(notNullValue())); - ExpressionParameter parameter = (ExpressionParameter) query.getSlicer(); - assertThat("Slicer exp is null.", parameter, is(notNullValue())); + ExpressionParameter parameter = (ExpressionParameter) query.getSlicer(); + assertThat("Slicer exp is null.", parameter, is(notNullValue())); - assertThat("Wrong member expression returned.", - parameter.getExpression(), is(equalTo("parameter"))); - } + assertThat("Wrong member expression returned.", + parameter.getExpression(), is(equalTo("parameter"))); + } - @Test - public void testParseMemberExpressionWithCalculation() throws Exception { - String mdx = "SELECT [Measures].[Store Sales] ON COLUMNS, [Product].[All Products] ON ROWS FROM [Sales] " - + "WHERE $['aaa' + 'bbb']"; + @Test + public void testParseMemberExpressionWithCalculation() throws Exception { + String mdx = "SELECT [Measures].[Store Sales] ON COLUMNS, [Product].[All Products] ON ROWS FROM [Sales] " + + "WHERE $['aaa' + 'bbb']"; - MdxStatement query = parseQuery(mdx); - assertThat("Failed to parse : " + mdx, query, is(notNullValue())); + MdxStatement query = parseQuery(mdx); + assertThat("Failed to parse : " + mdx, query, is(notNullValue())); - ExpressionParameter parameter = (ExpressionParameter) query.getSlicer(); - assertThat("Slicer exp is null.", parameter, is(notNullValue())); + ExpressionParameter parameter = (ExpressionParameter) query.getSlicer(); + assertThat("Slicer exp is null.", parameter, is(notNullValue())); - assertThat("Wrong member expression returned.", - parameter.getExpression(), is(equalTo("'aaa' + 'bbb'"))); - } + assertThat("Wrong member expression returned.", + parameter.getExpression(), is(equalTo("'aaa' + 'bbb'"))); + } - @Test - public void testParseMemberExpressionInWithMember() throws Exception { - String mdx = "WITH MEMBER [EXPR_MEMBER] AS '$[parameter]' SELECT [Measures].[Store Sales] ON COLUMNS, " - + "[Product].[All Products] ON ROWS FROM [Sales]"; + @Test + public void testParseMemberExpressionInWithMember() throws Exception { + String mdx = "WITH MEMBER [EXPR_MEMBER] AS '$[parameter]' SELECT [Measures].[Store Sales] ON COLUMNS, " + + "[Product].[All Products] ON ROWS FROM [Sales]"; - MdxStatement query = parseQuery(mdx); + MdxStatement query = parseQuery(mdx); - assertThat("Failed to parse : " + mdx, query, is(notNullValue())); + assertThat("Failed to parse : " + mdx, query, is(notNullValue())); - List formulas = query.getFormulas(); + List formulas = query.getFormulas(); - assertThat("Formula list is null.", formulas, is(notNullValue())); - assertThat("Wrong number of formula returned.", formulas.size(), - is(equalTo(1))); + assertThat("Formula list is null.", formulas, is(notNullValue())); + assertThat("Wrong number of formula returned.", formulas.size(), + is(equalTo(1))); - Formula formula = formulas.get(0); + Formula formula = formulas.get(0); - Exp exp = formula.getExp(); + Exp exp = formula.getExp(); - assertThat("Formula expression is null.", formulas, is(notNullValue())); - assertThat("Parameter expression type is wrong.", exp, - is(instanceOf(ExpressionParameter.class))); + assertThat("Formula expression is null.", formulas, is(notNullValue())); + assertThat("Parameter expression type is wrong.", exp, + is(instanceOf(ExpressionParameter.class))); - ExpressionParameter parameter = (ExpressionParameter) exp; + ExpressionParameter parameter = (ExpressionParameter) exp; - assertThat("Wrong parameter expression.", parameter.getExpression(), - is(equalTo("parameter"))); - } + assertThat("Wrong parameter expression.", parameter.getExpression(), + is(equalTo("parameter"))); + } - @Test - public void testParseMemberExpressionInWithSet() throws Exception { - String mdx = "WITH SET [EXPR_SET] AS {$[parameter1], [AAA].[BBB], $[parameter2]} " - + "SELECT [Measures].[Store Sales] ON COLUMNS, " - + "[Product].[All Products] ON ROWS FROM [Sales]"; + @Test + public void testParseMemberExpressionInWithSet() throws Exception { + String mdx = "WITH SET [EXPR_SET] AS {$[parameter1], [AAA].[BBB], $[parameter2]} " + + "SELECT [Measures].[Store Sales] ON COLUMNS, " + + "[Product].[All Products] ON ROWS FROM [Sales]"; - MdxStatement query = parseQuery(mdx); - assertThat("Failed to parse : " + mdx, query, is(notNullValue())); + MdxStatement query = parseQuery(mdx); + assertThat("Failed to parse : " + mdx, query, is(notNullValue())); - List formulas = query.getFormulas(); + List formulas = query.getFormulas(); - assertThat("Formula list is null.", formulas, is(notNullValue())); - assertThat("Wrong number of formula returned.", formulas.size(), - is(equalTo(1))); + assertThat("Formula list is null.", formulas, is(notNullValue())); + assertThat("Wrong number of formula returned.", formulas.size(), + is(equalTo(1))); - Formula formula = formulas.get(0); + Formula formula = formulas.get(0); - Exp exp = formula.getExp(); + Exp exp = formula.getExp(); - assertThat("Formula expression is null.", formulas, is(notNullValue())); - assertThat("Parameter expression type is wrong.", exp, - is(instanceOf(FunCall.class))); + assertThat("Formula expression is null.", formulas, is(notNullValue())); + assertThat("Parameter expression type is wrong.", exp, + is(instanceOf(FunCall.class))); - FunCall func = (FunCall) exp; + FunCall func = (FunCall) exp; - assertThat("Set member list is null.", func.getArgs(), - is(notNullValue())); - assertThat("Wrong number of set children returned.", func.getArgs() - .size(), is(equalTo(3))); + assertThat("Set member list is null.", func.getArgs(), + is(notNullValue())); + assertThat("Wrong number of set children returned.", func.getArgs() + .size(), is(equalTo(3))); - assertThat("First parameter expression type is wrong.", func.getArgs() - .get(0), is(instanceOf(ExpressionParameter.class))); - assertThat("Third parameter expression type is wrong.", func.getArgs() - .get(2), is(instanceOf(ExpressionParameter.class))); + assertThat("First parameter expression type is wrong.", func.getArgs() + .get(0), is(instanceOf(ExpressionParameter.class))); + assertThat("Third parameter expression type is wrong.", func.getArgs() + .get(2), is(instanceOf(ExpressionParameter.class))); - ExpressionParameter parameter1 = (ExpressionParameter) func.getArgs() - .get(0); - ExpressionParameter parameter3 = (ExpressionParameter) func.getArgs() - .get(2); + ExpressionParameter parameter1 = (ExpressionParameter) func.getArgs() + .get(0); + ExpressionParameter parameter3 = (ExpressionParameter) func.getArgs() + .get(2); - assertThat("Wrong parameter expression.", parameter1.getExpression(), - is(equalTo("parameter1"))); - assertThat("Wrong parameter expression.", parameter3.getExpression(), - is(equalTo("parameter2"))); - } + assertThat("Wrong parameter expression.", parameter1.getExpression(), + is(equalTo("parameter1"))); + assertThat("Wrong parameter expression.", parameter3.getExpression(), + is(equalTo("parameter2"))); + } - @Test - public void testParseMemberExpressionEscape() throws Exception { - String mdx = "SELECT [Measures].[Store Sales] ON COLUMNS, [Product].[All Products] ON ROWS FROM [Sales] " - + "WHERE $['#aaa' + '[1, 2, 3]]']"; + @Test + public void testParseMemberExpressionEscape() throws Exception { + String mdx = "SELECT [Measures].[Store Sales] ON COLUMNS, [Product].[All Products] ON ROWS FROM [Sales] " + + "WHERE $['#aaa' + '[1, 2, 3]]']"; - MdxStatement query = parseQuery(mdx); - assertThat("Failed to parse : " + mdx, query, is(notNullValue())); + MdxStatement query = parseQuery(mdx); + assertThat("Failed to parse : " + mdx, query, is(notNullValue())); - ExpressionParameter parameter = (ExpressionParameter) query.getSlicer(); - assertThat("Slicer exp is null.", parameter, is(notNullValue())); + ExpressionParameter parameter = (ExpressionParameter) query.getSlicer(); + assertThat("Slicer exp is null.", parameter, is(notNullValue())); - assertThat("Wrong member expression returned.", - parameter.getExpression(), is(equalTo("'#aaa' + '[1, 2, 3]'"))); - } + assertThat("Wrong member expression returned.", + parameter.getExpression(), is(equalTo("'#aaa' + '[1, 2, 3]'"))); + } - @Test - public void testParseValueExpression() throws Exception { - String mdx = "WITH MEMBER [Measures].[Calc Cost] AS '[Measures].[Store Cost] * ${ratio}' " - + "SELECT [Measures].[Calc Cost] ON COLUMNS FROM [Sales]"; + @Test + public void testParseValueExpression() throws Exception { + String mdx = "WITH MEMBER [Measures].[Calc Cost] AS '[Measures].[Store Cost] * ${ratio}' " + + "SELECT [Measures].[Calc Cost] ON COLUMNS FROM [Sales]"; - MdxStatement query = parseQuery(mdx); - assertThat("Failed to parse : " + mdx, query, is(notNullValue())); + MdxStatement query = parseQuery(mdx); + assertThat("Failed to parse : " + mdx, query, is(notNullValue())); - List formulas = query.getFormulas(); + List formulas = query.getFormulas(); - assertThat("Formula list not be null.", formulas, is(notNullValue())); - assertThat("Number of formula should be 1.", formulas.size(), - is(equalTo(1))); + assertThat("Formula list not be null.", formulas, is(notNullValue())); + assertThat("Number of formula should be 1.", formulas.size(), + is(equalTo(1))); - Formula formula = formulas.get(0); + Formula formula = formulas.get(0); - Exp arg = formula.getExp(); + Exp arg = formula.getExp(); - assertThat("Wrong argument type.", arg, is(instanceOf(FunCall.class))); + assertThat("Wrong argument type.", arg, is(instanceOf(FunCall.class))); - FunCall func = (FunCall) arg; + FunCall func = (FunCall) arg; - assertThat("Wrong number of function arguments.", - func.getArgs().size(), is(equalTo(2))); + assertThat("Wrong number of function arguments.", + func.getArgs().size(), is(equalTo(2))); - ValueParameter parameter = (ValueParameter) func.getArgs().get(1); - assertThat("Wrong value parameter expression.", - parameter.getExpression(), is(equalTo("ratio"))); - } + ValueParameter parameter = (ValueParameter) func.getArgs().get(1); + assertThat("Wrong value parameter expression.", + parameter.getExpression(), is(equalTo("ratio"))); + } - @Test - public void testParseWithMemberProperties() throws Exception { - String mdx = "WITH MEMBER [Measures].[address] AS " - + "'[Store].CurrentMember.Properties(\"Street address\")' " - + "SELECT NON EMPTY {[Measures].[address]} ON COLUMNS, " - + "NON EMPTY [Store].[USA].[CA].[Beverly Hills].Children ON ROWS from [Sales]"; + @Test + public void testParseWithMemberProperties() throws Exception { + String mdx = "WITH MEMBER [Measures].[address] AS " + + "'[Store].CurrentMember.Properties(\"Street address\")' " + + "SELECT NON EMPTY {[Measures].[address]} ON COLUMNS, " + + "NON EMPTY [Store].[USA].[CA].[Beverly Hills].Children ON ROWS from [Sales]"; - MdxStatement query = parseQuery(mdx); - assertThat("Failed to parse : " + mdx, query, is(notNullValue())); - } + MdxStatement query = parseQuery(mdx); + assertThat("Failed to parse : " + mdx, query, is(notNullValue())); + } } diff --git a/pivot4j-core/src/test/java/org/pivot4j/state/StateSavingIT.java b/pivot4j-core/src/test/java/org/pivot4j/state/StateSavingIT.java index e4d04c4c..74638143 100644 --- a/pivot4j-core/src/test/java/org/pivot4j/state/StateSavingIT.java +++ b/pivot4j-core/src/test/java/org/pivot4j/state/StateSavingIT.java @@ -32,130 +32,129 @@ public class StateSavingIT extends AbstractIntegrationTestCase { - private String testQuery = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales] WHERE [Time].[1997]"; - - /** - * @return the testQuery - */ - public String getTestQuery() { - return testQuery; - } - - /** - * @param testQuery - * the testQuery to set - */ - public void setTestQuery(String testQuery) { - this.testQuery = testQuery; - } - - @Test - public void testBookmarkModelState() { - PivotModel model = getPivotModel(); - model.setMdx(getTestQuery()); - model.initialize(); - - model.setSorting(true); - model.setTopBottomCount(3); - model.setSortCriteria(SortCriteria.BOTTOMCOUNT); - - CellSet cellSet = model.getCellSet(); - CellSetAxis axis = cellSet.getAxes().get(Axis.COLUMNS.axisOrdinal()); - - model.sort(axis, axis.getPositions().get(0)); - - String mdx = model.getCurrentMdx(); - - Serializable bookmark = model.saveState(); - - assertThat("Bookmarked state should not be null", bookmark, - is(notNullValue())); - - PivotModel newModel = new PivotModelImpl(getDataSource()); - newModel.restoreState(bookmark); - - newModel.getCellSet(); - - String newMdx = newModel.getCurrentMdx(); - if (newMdx != null) { - // Currently the parser treats every number as double value. - // It's inevitable now and does not impact the result. - newMdx = newMdx.replaceAll("3\\.0", "3"); - } - - assertThat("MDX has been changed after the state restoration", newMdx, - is(equalTo(mdx))); - assertThat( - "RenderProperty 'sorting' has been changed after the state restoration", - newModel.isSorting(), is(true)); - assertThat( - "RenderProperty 'topBottomCount' has been changed after the state restoration", - newModel.getTopBottomCount(), is(equalTo(3))); - assertThat( - "RenderProperty 'sortMode' has been changed after the state restoration", - newModel.getSortCriteria(), - is(equalTo(SortCriteria.BOTTOMCOUNT))); - } - - @Test - public void testSaveModelSettings() throws ConfigurationException, - IOException { - PivotModel model = getPivotModel(); - model.setMdx(getTestQuery()); - model.initialize(); - - model.setSorting(true); - model.setTopBottomCount(3); - model.setSortCriteria(SortCriteria.BOTTOMCOUNT); - - CellSet cellSet = model.getCellSet(); - CellSetAxis axis = cellSet.getAxes().get(Axis.COLUMNS.axisOrdinal()); - - model.sort(axis, axis.getPositions().get(0)); - - String mdx = model.getCurrentMdx(); - - XMLConfiguration configuration = new XMLConfiguration(); - configuration.setDelimiterParsingDisabled(true); - - model.saveSettings(configuration); - - Logger logger = LoggerFactory.getLogger(getClass()); - if (logger.isDebugEnabled()) { - StringWriter writer = new StringWriter(); - configuration.save(writer); - writer.flush(); - writer.close(); - - logger.debug("Loading report content :" - + System.getProperty("line.separator")); - logger.debug(writer.getBuffer().toString()); - } - - PivotModel newModel = new PivotModelImpl(getDataSource()); - newModel.restoreSettings(configuration); - - newModel.getCellSet(); - - String newMdx = newModel.getCurrentMdx(); - if (newMdx != null) { - // Currently the parser treats every number as double value. - // It's inevitable now and does not impact the result. - newMdx = newMdx.replaceAll("3\\.0", "3"); - } - - assertThat("MDX has been changed after the state restoration", newMdx, - is(equalTo(mdx))); - assertThat( - "RenderProperty 'sorting' has been changed after the state restoration", - newModel.isSorting(), is(true)); - assertThat( - "RenderProperty 'topBottomCount' has been changed after the state restoration", - newModel.getTopBottomCount(), is(equalTo(3))); - assertThat( - "RenderProperty 'sortMode' has been changed after the state restoration", - newModel.getSortCriteria(), - is(equalTo(SortCriteria.BOTTOMCOUNT))); - } + private String testQuery = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales] WHERE [Time].[1997]"; + + /** + * @return the testQuery + */ + public String getTestQuery() { + return testQuery; + } + + /** + * @param testQuery the testQuery to set + */ + public void setTestQuery(String testQuery) { + this.testQuery = testQuery; + } + + @Test + public void testBookmarkModelState() { + PivotModel model = getPivotModel(); + model.setMdx(getTestQuery()); + model.initialize(); + + model.setSorting(true); + model.setTopBottomCount(3); + model.setSortCriteria(SortCriteria.BOTTOMCOUNT); + + CellSet cellSet = model.getCellSet(); + CellSetAxis axis = cellSet.getAxes().get(Axis.COLUMNS.axisOrdinal()); + + model.sort(axis, axis.getPositions().get(0)); + + String mdx = model.getCurrentMdx(); + + Serializable bookmark = model.saveState(); + + assertThat("Bookmarked state should not be null", bookmark, + is(notNullValue())); + + PivotModel newModel = new PivotModelImpl(getDataSource()); + newModel.restoreState(bookmark); + + newModel.getCellSet(); + + String newMdx = newModel.getCurrentMdx(); + if (newMdx != null) { + // Currently the parser treats every number as double value. + // It's inevitable now and does not impact the result. + newMdx = newMdx.replaceAll("3\\.0", "3"); + } + + assertThat("MDX has been changed after the state restoration", newMdx, + is(equalTo(mdx))); + assertThat( + "RenderProperty 'sorting' has been changed after the state restoration", + newModel.isSorting(), is(true)); + assertThat( + "RenderProperty 'topBottomCount' has been changed after the state restoration", + newModel.getTopBottomCount(), is(equalTo(3))); + assertThat( + "RenderProperty 'sortMode' has been changed after the state restoration", + newModel.getSortCriteria(), + is(equalTo(SortCriteria.BOTTOMCOUNT))); + } + + @Test + public void testSaveModelSettings() throws ConfigurationException, + IOException { + PivotModel model = getPivotModel(); + model.setMdx(getTestQuery()); + model.initialize(); + + model.setSorting(true); + model.setTopBottomCount(3); + model.setSortCriteria(SortCriteria.BOTTOMCOUNT); + + CellSet cellSet = model.getCellSet(); + CellSetAxis axis = cellSet.getAxes().get(Axis.COLUMNS.axisOrdinal()); + + model.sort(axis, axis.getPositions().get(0)); + + String mdx = model.getCurrentMdx(); + + XMLConfiguration configuration = new XMLConfiguration(); + configuration.setDelimiterParsingDisabled(true); + + model.saveSettings(configuration); + + Logger logger = LoggerFactory.getLogger(getClass()); + if (logger.isDebugEnabled()) { + StringWriter writer = new StringWriter(); + configuration.save(writer); + writer.flush(); + writer.close(); + + logger.debug("Loading report content :" + + System.getProperty("line.separator")); + logger.debug(writer.getBuffer().toString()); + } + + PivotModel newModel = new PivotModelImpl(getDataSource()); + newModel.restoreSettings(configuration); + + newModel.getCellSet(); + + String newMdx = newModel.getCurrentMdx(); + if (newMdx != null) { + // Currently the parser treats every number as double value. + // It's inevitable now and does not impact the result. + newMdx = newMdx.replaceAll("3\\.0", "3"); + } + + assertThat("MDX has been changed after the state restoration", newMdx, + is(equalTo(mdx))); + assertThat( + "RenderProperty 'sorting' has been changed after the state restoration", + newModel.isSorting(), is(true)); + assertThat( + "RenderProperty 'topBottomCount' has been changed after the state restoration", + newModel.getTopBottomCount(), is(equalTo(3))); + assertThat( + "RenderProperty 'sortMode' has been changed after the state restoration", + newModel.getSortCriteria(), + is(equalTo(SortCriteria.BOTTOMCOUNT))); + } } diff --git a/pivot4j-core/src/test/java/org/pivot4j/transform/impl/AbstractTransformTestCase.java b/pivot4j-core/src/test/java/org/pivot4j/transform/impl/AbstractTransformTestCase.java index 57ecf6a6..8710f8c2 100644 --- a/pivot4j-core/src/test/java/org/pivot4j/transform/impl/AbstractTransformTestCase.java +++ b/pivot4j-core/src/test/java/org/pivot4j/transform/impl/AbstractTransformTestCase.java @@ -15,41 +15,41 @@ import org.pivot4j.transform.Transform; public abstract class AbstractTransformTestCase extends - AbstractIntegrationTestCase { + AbstractIntegrationTestCase { - private T transform; + private T transform; - /** - * @see org.pivot4j.AbstractIntegrationTestCase#setUp() - */ - @Override - public void setUp() throws Exception { - super.setUp(); + /** + * @see org.pivot4j.AbstractIntegrationTestCase#setUp() + */ + @Override + public void setUp() throws Exception { + super.setUp(); - PivotModel model = getPivotModel(); - model.setMdx(getInitialQuery()); - model.initialize(); + PivotModel model = getPivotModel(); + model.setMdx(getInitialQuery()); + model.initialize(); - this.transform = model.getTransform(getType()); + this.transform = model.getTransform(getType()); - assertNotNull("No suitable transform found for " + getType(), transform); - } + assertNotNull("No suitable transform found for " + getType(), transform); + } - /** - * @throws Exception - * @see org.pivot4j.AbstractIntegrationTestCase#tearDown() - */ - @Override - public void tearDown() throws Exception { - super.tearDown(); - this.transform = null; - } + /** + * @throws Exception + * @see org.pivot4j.AbstractIntegrationTestCase#tearDown() + */ + @Override + public void tearDown() throws Exception { + super.tearDown(); + this.transform = null; + } - protected abstract Class getType(); + protected abstract Class getType(); - protected abstract String getInitialQuery(); + protected abstract String getInitialQuery(); - protected T getTransform() { - return transform; - } + protected T getTransform() { + return transform; + } } diff --git a/pivot4j-core/src/test/java/org/pivot4j/transform/impl/ChangeSlicerImplIT.java b/pivot4j-core/src/test/java/org/pivot4j/transform/impl/ChangeSlicerImplIT.java index 34916b52..56486db5 100644 --- a/pivot4j-core/src/test/java/org/pivot4j/transform/impl/ChangeSlicerImplIT.java +++ b/pivot4j-core/src/test/java/org/pivot4j/transform/impl/ChangeSlicerImplIT.java @@ -25,252 +25,253 @@ public class ChangeSlicerImplIT extends AbstractTransformTestCase { - private String initialQuery = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales] WHERE [Time].[1997]"; + private String initialQuery = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales] WHERE [Time].[1997]"; - /** - * @return the initialQuery - * @see org.pivot4j.transform.impl.AbstractTransformTestCase#getInitialQuery() - */ - protected String getInitialQuery() { - return initialQuery; - } + /** + * @return the initialQuery + * @see + * org.pivot4j.transform.impl.AbstractTransformTestCase#getInitialQuery() + */ + protected String getInitialQuery() { + return initialQuery; + } - /** - * @see org.pivot4j.transform.impl.AbstractTransformTestCase#getType() - */ - @Override - protected Class getType() { - return ChangeSlicer.class; - } + /** + * @see org.pivot4j.transform.impl.AbstractTransformTestCase#getType() + */ + @Override + protected Class getType() { + return ChangeSlicer.class; + } - @Test - public void testGetSlicers() { - ChangeSlicer transform = getTransform(); + @Test + public void testGetSlicers() { + ChangeSlicer transform = getTransform(); - List members = transform.getSlicer(); + List members = transform.getSlicer(); - assertThat("Failed to retrieve slicer members", members, - is(notNullValue())); - assertThat("Failed to retrieve slicer members", members.isEmpty(), - is(false)); - } + assertThat("Failed to retrieve slicer members", members, + is(notNullValue())); + assertThat("Failed to retrieve slicer members", members.isEmpty(), + is(false)); + } - @Test - public void testSetSlicerWithSingleMember() throws OlapException { - ChangeSlicer transform = getTransform(); + @Test + public void testSetSlicerWithSingleMember() throws OlapException { + ChangeSlicer transform = getTransform(); - List members = new ArrayList(1); + List members = new ArrayList(1); - Cube cube = getPivotModel().getCube(); + Cube cube = getPivotModel().getCube(); - Member year1998 = cube.lookupMember(IdentifierNode.parseIdentifier( - "[Time].[1998]").getSegmentList()); + Member year1998 = cube.lookupMember(IdentifierNode.parseIdentifier( + "[Time].[1998]").getSegmentList()); - assertThat("Cannot look up member [Time].[1998]", year1998, - is(notNullValue())); + assertThat("Cannot look up member [Time].[1998]", year1998, + is(notNullValue())); - members.add(year1998); + members.add(year1998); - transform.setSlicer(members); + transform.setSlicer(members); - getPivotModel().getCellSet(); + getPivotModel().getCellSet(); - assertThat( - getPivotModel().getCurrentMdx(), - is(equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS " - + "FROM [Sales] WHERE [Time].[1998]"))); - } + assertThat( + getPivotModel().getCurrentMdx(), + is(equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS " + + "FROM [Sales] WHERE [Time].[1998]"))); + } - @Test - public void testSetSlicerWithSet() throws OlapException { - ChangeSlicer transform = getTransform(); + @Test + public void testSetSlicerWithSet() throws OlapException { + ChangeSlicer transform = getTransform(); - List members = new ArrayList(2); + List members = new ArrayList(2); - Cube cube = getPivotModel().getCube(); + Cube cube = getPivotModel().getCube(); - Member year1997 = cube.lookupMember(IdentifierNode.parseIdentifier( - "[Time].[1997]").getSegmentList()); - Member year1998 = cube.lookupMember(IdentifierNode.parseIdentifier( - "[Time].[1998]").getSegmentList()); + Member year1997 = cube.lookupMember(IdentifierNode.parseIdentifier( + "[Time].[1997]").getSegmentList()); + Member year1998 = cube.lookupMember(IdentifierNode.parseIdentifier( + "[Time].[1998]").getSegmentList()); - assertThat("Cannot look up member [Time].[1997]", year1997, - is(notNullValue())); - assertThat("Cannot look up member [Time].[1998]", year1998, - is(notNullValue())); + assertThat("Cannot look up member [Time].[1997]", year1997, + is(notNullValue())); + assertThat("Cannot look up member [Time].[1998]", year1998, + is(notNullValue())); - members.add(year1997); - members.add(year1998); + members.add(year1997); + members.add(year1998); - transform.setSlicer(members); + transform.setSlicer(members); - getPivotModel().getCellSet(); + getPivotModel().getCellSet(); - assertThat( - getPivotModel().getCurrentMdx(), - is(equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales] " - + "WHERE {[Time].[1997], [Time].[1998]}"))); - } + assertThat( + getPivotModel().getCurrentMdx(), + is(equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales] " + + "WHERE {[Time].[1997], [Time].[1998]}"))); + } - @Test - public void testSetSlicerWithTuple() throws OlapException { - ChangeSlicer transform = getTransform(); + @Test + public void testSetSlicerWithTuple() throws OlapException { + ChangeSlicer transform = getTransform(); - List members = new ArrayList(2); + List members = new ArrayList(2); - Cube cube = getPivotModel().getCube(); + Cube cube = getPivotModel().getCube(); - Member year1997 = cube.lookupMember(IdentifierNode.parseIdentifier( - "[Time].[1997]").getSegmentList()); - assertThat("Cannot look up member [Time].[1997]", year1997, - is(notNullValue())); + Member year1997 = cube.lookupMember(IdentifierNode.parseIdentifier( + "[Time].[1997]").getSegmentList()); + assertThat("Cannot look up member [Time].[1997]", year1997, + is(notNullValue())); - Member year1998 = cube.lookupMember(IdentifierNode.parseIdentifier( - "[Time].[1998]").getSegmentList()); - assertThat("Cannot look up member [Time].[1998]", year1998, - is(notNullValue())); + Member year1998 = cube.lookupMember(IdentifierNode.parseIdentifier( + "[Time].[1998]").getSegmentList()); + assertThat("Cannot look up member [Time].[1998]", year1998, + is(notNullValue())); - Member genderM = cube.lookupMember(IdentifierNode.parseIdentifier( - "[Gender].[M]").getSegmentList()); + Member genderM = cube.lookupMember(IdentifierNode.parseIdentifier( + "[Gender].[M]").getSegmentList()); - assertThat("Cannot look up member [Gender].[M]", genderM, - is(notNullValue())); + assertThat("Cannot look up member [Gender].[M]", genderM, + is(notNullValue())); - members.add(year1997); - members.add(year1998); - members.add(genderM); + members.add(year1997); + members.add(year1998); + members.add(genderM); - transform.setSlicer(members); + transform.setSlicer(members); - getPivotModel().getCellSet(); + getPivotModel().getCellSet(); - assertThat( - getPivotModel().getCurrentMdx(), - is(equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales] " - + "WHERE CrossJoin({[Time].[1997], [Time].[1998]}, [Gender].[M])"))); - } + assertThat( + getPivotModel().getCurrentMdx(), + is(equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales] " + + "WHERE CrossJoin({[Time].[1997], [Time].[1998]}, [Gender].[M])"))); + } - @Test - public void testSetSlicerWithHierarchy() throws OlapException { - ChangeSlicer transform = getTransform(); + @Test + public void testSetSlicerWithHierarchy() throws OlapException { + ChangeSlicer transform = getTransform(); - Cube cube = getPivotModel().getCube(); + Cube cube = getPivotModel().getCube(); - Member year1997 = cube.lookupMember(IdentifierNode.parseIdentifier( - "[Time].[1997]").getSegmentList()); - assertThat("Cannot look up member [Time].[1997]", year1997, - is(notNullValue())); + Member year1997 = cube.lookupMember(IdentifierNode.parseIdentifier( + "[Time].[1997]").getSegmentList()); + assertThat("Cannot look up member [Time].[1997]", year1997, + is(notNullValue())); - Member genderM = cube.lookupMember(IdentifierNode.parseIdentifier( - "[Gender].[M]").getSegmentList()); + Member genderM = cube.lookupMember(IdentifierNode.parseIdentifier( + "[Gender].[M]").getSegmentList()); - assertThat("Cannot look up member [Gender].[M]", genderM, - is(notNullValue())); + assertThat("Cannot look up member [Gender].[M]", genderM, + is(notNullValue())); - List timeMembers = new ArrayList(1); - timeMembers.add(year1997); + List timeMembers = new ArrayList(1); + timeMembers.add(year1997); - List genderMembers = new ArrayList(1); - genderMembers.add(genderM); + List genderMembers = new ArrayList(1); + genderMembers.add(genderM); - transform.setSlicer(year1997.getHierarchy(), timeMembers); - transform.setSlicer(genderM.getHierarchy(), genderMembers); + transform.setSlicer(year1997.getHierarchy(), timeMembers); + transform.setSlicer(genderM.getHierarchy(), genderMembers); - getPivotModel().getCellSet(); + getPivotModel().getCellSet(); - assertThat( - getPivotModel().getCurrentMdx(), - is(equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales] " - + "WHERE CrossJoin([Time].[1997], [Gender].[M])"))); - } + assertThat( + getPivotModel().getCurrentMdx(), + is(equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales] " + + "WHERE CrossJoin([Time].[1997], [Gender].[M])"))); + } - @Test - public void testSetSlicerWithManyHierarchies() throws OlapException { - ChangeSlicer transform = getTransform(); + @Test + public void testSetSlicerWithManyHierarchies() throws OlapException { + ChangeSlicer transform = getTransform(); - Cube cube = getPivotModel().getCube(); + Cube cube = getPivotModel().getCube(); - Member year1997 = cube.lookupMember(IdentifierNode.parseIdentifier( - "[Time].[1997]").getSegmentList()); - assertThat("Cannot look up member [Time].[1997]", year1997, - is(notNullValue())); + Member year1997 = cube.lookupMember(IdentifierNode.parseIdentifier( + "[Time].[1997]").getSegmentList()); + assertThat("Cannot look up member [Time].[1997]", year1997, + is(notNullValue())); - Member genderM = cube.lookupMember(IdentifierNode.parseIdentifier( - "[Gender].[M]").getSegmentList()); + Member genderM = cube.lookupMember(IdentifierNode.parseIdentifier( + "[Gender].[M]").getSegmentList()); - assertThat("Cannot look up member [Gender].[M]", genderM, - is(notNullValue())); + assertThat("Cannot look up member [Gender].[M]", genderM, + is(notNullValue())); - Member maritalStatusS = cube.lookupMember(IdentifierNode - .parseIdentifier("[Marital Status].[S]").getSegmentList()); + Member maritalStatusS = cube.lookupMember(IdentifierNode + .parseIdentifier("[Marital Status].[S]").getSegmentList()); - assertThat("Cannot look up member [Marital Status].[S]", - maritalStatusS, is(notNullValue())); + assertThat("Cannot look up member [Marital Status].[S]", + maritalStatusS, is(notNullValue())); - List timeMembers = new ArrayList(1); - timeMembers.add(year1997); + List timeMembers = new ArrayList(1); + timeMembers.add(year1997); - List genderMembers = new ArrayList(1); - genderMembers.add(genderM); + List genderMembers = new ArrayList(1); + genderMembers.add(genderM); - List maritalStatusMembers = new ArrayList(1); - maritalStatusMembers.add(maritalStatusS); + List maritalStatusMembers = new ArrayList(1); + maritalStatusMembers.add(maritalStatusS); - transform.setSlicer(year1997.getHierarchy(), timeMembers); - transform.setSlicer(genderM.getHierarchy(), genderMembers); - transform - .setSlicer(maritalStatusS.getHierarchy(), maritalStatusMembers); + transform.setSlicer(year1997.getHierarchy(), timeMembers); + transform.setSlicer(genderM.getHierarchy(), genderMembers); + transform + .setSlicer(maritalStatusS.getHierarchy(), maritalStatusMembers); - getPivotModel().getCellSet(); + getPivotModel().getCellSet(); - assertThat( - getPivotModel().getCurrentMdx(), - is(equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales] " - + "WHERE CrossJoin(CrossJoin([Time].[1997], [Gender].[M]), [Marital Status].[S])"))); - } + assertThat( + getPivotModel().getCurrentMdx(), + is(equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales] " + + "WHERE CrossJoin(CrossJoin([Time].[1997], [Gender].[M]), [Marital Status].[S])"))); + } - @Test - public void testSetSlicerWithManyHierarchies2() throws OlapException { - ChangeSlicer transform = getTransform(); + @Test + public void testSetSlicerWithManyHierarchies2() throws OlapException { + ChangeSlicer transform = getTransform(); - Cube cube = getPivotModel().getCube(); + Cube cube = getPivotModel().getCube(); - Member year1997 = cube.lookupMember(IdentifierNode.parseIdentifier( - "[Time].[1997]").getSegmentList()); - assertThat("Cannot look up member [Time].[1997]", year1997, - is(notNullValue())); + Member year1997 = cube.lookupMember(IdentifierNode.parseIdentifier( + "[Time].[1997]").getSegmentList()); + assertThat("Cannot look up member [Time].[1997]", year1997, + is(notNullValue())); - Member genderM = cube.lookupMember(IdentifierNode.parseIdentifier( - "[Gender].[M]").getSegmentList()); + Member genderM = cube.lookupMember(IdentifierNode.parseIdentifier( + "[Gender].[M]").getSegmentList()); - assertThat("Cannot look up member [Gender].[M]", genderM, - is(notNullValue())); + assertThat("Cannot look up member [Gender].[M]", genderM, + is(notNullValue())); - Member maritalStatusS = cube.lookupMember(IdentifierNode - .parseIdentifier("[Marital Status].[S]").getSegmentList()); + Member maritalStatusS = cube.lookupMember(IdentifierNode + .parseIdentifier("[Marital Status].[S]").getSegmentList()); - assertThat("Cannot look up member [Marital Status].[S]", - maritalStatusS, is(notNullValue())); + assertThat("Cannot look up member [Marital Status].[S]", + maritalStatusS, is(notNullValue())); - List members = new ArrayList(3); - members.add(year1997); - members.add(genderM); - members.add(maritalStatusS); + List members = new ArrayList(3); + members.add(year1997); + members.add(genderM); + members.add(maritalStatusS); - transform.setSlicer(members); + transform.setSlicer(members); - getPivotModel().getCellSet(); + getPivotModel().getCellSet(); - assertThat( - getPivotModel().getCurrentMdx(), - is(equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales] " - + "WHERE CrossJoin(CrossJoin([Time].[1997], [Gender].[M]), [Marital Status].[S])"))); - } + assertThat( + getPivotModel().getCurrentMdx(), + is(equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales] " + + "WHERE CrossJoin(CrossJoin([Time].[1997], [Gender].[M]), [Marital Status].[S])"))); + } } diff --git a/pivot4j-core/src/test/java/org/pivot4j/transform/impl/DrillExpandMemberImplIT.java b/pivot4j-core/src/test/java/org/pivot4j/transform/impl/DrillExpandMemberImplIT.java index ef1b9862..dff94388 100644 --- a/pivot4j-core/src/test/java/org/pivot4j/transform/impl/DrillExpandMemberImplIT.java +++ b/pivot4j-core/src/test/java/org/pivot4j/transform/impl/DrillExpandMemberImplIT.java @@ -22,82 +22,83 @@ import org.pivot4j.transform.DrillExpandMember; public class DrillExpandMemberImplIT extends - AbstractTransformTestCase { - - private String initialQuery = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "Hierarchize({([Time].[1997], [Promotion Media].[All Media]), ([Time].[1998], [Promotion Media].[All Media])}) ON ROWS FROM [Sales]"; - - private String transformedQuery = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "Hierarchize(Union(Union(CrossJoin({[Time].[1997]}, {[Promotion Media].[All Media]}), CrossJoin({[Time].[1997]}, " - + "[Promotion Media].[All Media].Children)), Union(CrossJoin({[Time].[1998]}, {[Promotion Media].[All Media]}), " - + "CrossJoin({[Time].[1998]}, [Promotion Media].[All Media].Children)))) ON ROWS FROM [Sales]"; - - /** - * @return the initialQuery - * @see org.pivot4j.transform.impl.AbstractTransformTestCase#getInitialQuery() - */ - protected String getInitialQuery() { - return initialQuery; - } - - /** - * @return the transformedQuery - */ - protected String getTransformedQuery() { - return transformedQuery; - } - - /** - * @see org.pivot4j.transform.impl.AbstractTransformTestCase#getType() - */ - @Override - protected Class getType() { - return DrillExpandMember.class; - } - - @Test - public void testTransform() { - DrillExpandMember transform = getTransform(); - - PivotModel model = getPivotModel(); - - CellSet cellSet = model.getCellSet(); - assertThat("Unable to execute MDX query : " + getInitialQuery(), - cellSet, is(notNullValue())); - - CellSetAxis axis = cellSet.getAxes().get(1); - Position position = axis.getPositions().get(0); - - Member allMedia = position.getMembers().get(1); - - assertThat( - "Unexpected member at drill position : " - + allMedia.getCaption(), allMedia.getCaption(), - is(equalTo("All Media"))); - - assertThat("[All Media] should not be collapsible initially", - transform.canCollapse(allMedia), is(false)); - assertThat("[All Media] should be expandable initially", - transform.canExpand(allMedia), is(true)); - - transform.expand(allMedia); - - assertThat("Unexpected MDX after drill down : ", model.getCurrentMdx(), - is(equalTo(getTransformedQuery()))); - - assertThat("[All Media] should be collapsible after drill down", - transform.canCollapse(allMedia), is(true)); - assertThat("[All Media] should not be expandable after drill down", - transform.canExpand(allMedia), is(false)); - - transform.collapse(allMedia); - - assertThat("Unexpected MDX after collapse : ", model.getCurrentMdx(), - is(equalTo(getInitialQuery()))); - - assertThat("[All Media] should not be collapsible after collapse", - transform.canCollapse(allMedia), is(false)); - assertThat("[All Media] should be expandable after collapse", - transform.canExpand(allMedia), is(true)); - } + AbstractTransformTestCase { + + private String initialQuery = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "Hierarchize({([Time].[1997], [Promotion Media].[All Media]), ([Time].[1998], [Promotion Media].[All Media])}) ON ROWS FROM [Sales]"; + + private String transformedQuery = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "Hierarchize(Union(Union(CrossJoin({[Time].[1997]}, {[Promotion Media].[All Media]}), CrossJoin({[Time].[1997]}, " + + "[Promotion Media].[All Media].Children)), Union(CrossJoin({[Time].[1998]}, {[Promotion Media].[All Media]}), " + + "CrossJoin({[Time].[1998]}, [Promotion Media].[All Media].Children)))) ON ROWS FROM [Sales]"; + + /** + * @return the initialQuery + * @see + * org.pivot4j.transform.impl.AbstractTransformTestCase#getInitialQuery() + */ + protected String getInitialQuery() { + return initialQuery; + } + + /** + * @return the transformedQuery + */ + protected String getTransformedQuery() { + return transformedQuery; + } + + /** + * @see org.pivot4j.transform.impl.AbstractTransformTestCase#getType() + */ + @Override + protected Class getType() { + return DrillExpandMember.class; + } + + @Test + public void testTransform() { + DrillExpandMember transform = getTransform(); + + PivotModel model = getPivotModel(); + + CellSet cellSet = model.getCellSet(); + assertThat("Unable to execute MDX query : " + getInitialQuery(), + cellSet, is(notNullValue())); + + CellSetAxis axis = cellSet.getAxes().get(1); + Position position = axis.getPositions().get(0); + + Member allMedia = position.getMembers().get(1); + + assertThat( + "Unexpected member at drill position : " + + allMedia.getCaption(), allMedia.getCaption(), + is(equalTo("All Media"))); + + assertThat("[All Media] should not be collapsible initially", + transform.canCollapse(allMedia), is(false)); + assertThat("[All Media] should be expandable initially", + transform.canExpand(allMedia), is(true)); + + transform.expand(allMedia); + + assertThat("Unexpected MDX after drill down : ", model.getCurrentMdx(), + is(equalTo(getTransformedQuery()))); + + assertThat("[All Media] should be collapsible after drill down", + transform.canCollapse(allMedia), is(true)); + assertThat("[All Media] should not be expandable after drill down", + transform.canExpand(allMedia), is(false)); + + transform.collapse(allMedia); + + assertThat("Unexpected MDX after collapse : ", model.getCurrentMdx(), + is(equalTo(getInitialQuery()))); + + assertThat("[All Media] should not be collapsible after collapse", + transform.canCollapse(allMedia), is(false)); + assertThat("[All Media] should be expandable after collapse", + transform.canExpand(allMedia), is(true)); + } } diff --git a/pivot4j-core/src/test/java/org/pivot4j/transform/impl/DrillExpandPositionImplIT.java b/pivot4j-core/src/test/java/org/pivot4j/transform/impl/DrillExpandPositionImplIT.java index b8f9fd72..c3bb08e8 100644 --- a/pivot4j-core/src/test/java/org/pivot4j/transform/impl/DrillExpandPositionImplIT.java +++ b/pivot4j-core/src/test/java/org/pivot4j/transform/impl/DrillExpandPositionImplIT.java @@ -23,144 +23,145 @@ import org.pivot4j.transform.DrillExpandPosition; public class DrillExpandPositionImplIT extends - AbstractTransformTestCase { + AbstractTransformTestCase { - private String initialQuery = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "Hierarchize({([Time].[1997], [Promotion Media].[All Media]), ([Time].[1998], [Promotion Media].[All Media])}) ON ROWS FROM [Sales]"; + private String initialQuery = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "Hierarchize({([Time].[1997], [Promotion Media].[All Media]), ([Time].[1998], [Promotion Media].[All Media])}) ON ROWS FROM [Sales]"; - private String transformedQuery = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "Hierarchize(Union(Union(CrossJoin({[Time].[1997]}, {[Promotion Media].[All Media]}), " - + "CrossJoin({[Time].[1997]}, [Promotion Media].[All Media].Children)), " - + "{([Time].[1998], [Promotion Media].[All Media])})) ON ROWS FROM [Sales]"; + private String transformedQuery = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "Hierarchize(Union(Union(CrossJoin({[Time].[1997]}, {[Promotion Media].[All Media]}), " + + "CrossJoin({[Time].[1997]}, [Promotion Media].[All Media].Children)), " + + "{([Time].[1998], [Promotion Media].[All Media])})) ON ROWS FROM [Sales]"; - /** - * @return the initialQuery - * @see org.pivot4j.transform.impl.AbstractTransformTestCase#getInitialQuery() - */ - protected String getInitialQuery() { - return initialQuery; - } + /** + * @return the initialQuery + * @see + * org.pivot4j.transform.impl.AbstractTransformTestCase#getInitialQuery() + */ + protected String getInitialQuery() { + return initialQuery; + } - /** - * @return the transformedQuery - */ - protected String getTransformedQuery() { - return transformedQuery; - } + /** + * @return the transformedQuery + */ + protected String getTransformedQuery() { + return transformedQuery; + } - /** - * @see org.pivot4j.transform.impl.AbstractTransformTestCase#getType() - */ - @Override - protected Class getType() { - return DrillExpandPosition.class; - } - - @Test - public void testExpandOnPosition() { - DrillExpandPosition transform = getTransform(); - - PivotModel model = getPivotModel(); - - CellSet cellSet = model.getCellSet(); - assertThat("Unable to execute MDX query : " + getInitialQuery(), - cellSet, is(notNullValue())); - - CellSetAxis axis = cellSet.getAxes().get(1); - Position position = axis.getPositions().get(0); - - Member allMedia = position.getMembers().get(1); - - assertThat( - "Unexpected member at drill position : " - + allMedia.getCaption(), allMedia.getCaption(), - is(equalTo("All Media"))); - - assertThat("[All Media] should not be collapsible initially", - transform.canCollapse(position, allMedia), is(false)); - assertThat("[All Media] should be expandable initially", - transform.canExpand(position, allMedia), is(true)); - - transform.expand(position, allMedia); - - assertThat("Unexpected MDX after drill down : ", model.getCurrentMdx(), - is(equalTo(getTransformedQuery()))); - - assertThat("[All Media] should be collapsible after drill down", - transform.canCollapse(position, allMedia), is(true)); - assertThat("[All Media] should not be expandable after drill down", - transform.canExpand(position, allMedia), is(false)); - - transform.collapse(position, allMedia); - - assertThat("Unexpected MDX after collapse : ", model.getCurrentMdx(), - is(equalTo(getInitialQuery()))); - - assertThat("[All Media] should not be collapsible after collapse", - transform.canCollapse(position, allMedia), is(false)); - assertThat("[All Media] should be expandable after collapse", - transform.canExpand(position, allMedia), is(true)); - } - - @Test - public void testExpandWithSort() { - DrillExpandPosition transform = getTransform(); - - PivotModel model = getPivotModel(); - - CellSet cellSet = model.getCellSet(); - assertThat("Unable to execute MDX query : " + getInitialQuery(), - cellSet, is(notNullValue())); - - CellSetAxis axis = cellSet.getAxes().get(1); - Position position = axis.getPositions().get(0); - - Member allMedia = position.getMembers().get(1); - - assertThat( - "Unexpected member at drill position : " - + allMedia.getCaption(), allMedia.getCaption(), - is(equalTo("All Media"))); - - model.setSorting(true); - model.setTopBottomCount(3); - model.setSortCriteria(SortCriteria.BOTTOMCOUNT); - - model.sort(axis, position); - - assertThat("[All Media] should not be collapsible initially", - transform.canCollapse(position, allMedia), is(false)); - assertThat("[All Media] should be expandable initially", - transform.canExpand(position, allMedia), is(true)); - - transform.expand(position, allMedia); - - assertThat( - "Unexpected MDX after drill down : ", - model.getCurrentMdx(), - is(equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "BottomCount(Union(Union(CrossJoin({[Time].[1997]}, {[Promotion Media].[All Media]}), " - + "CrossJoin({[Time].[1997]}, [Promotion Media].[All Media].Children)), {([Time].[1998], " - + "[Promotion Media].[All Media])}), 3, ([Time].[1997], [Promotion Media].[All Media])) ON ROWS FROM [Sales]"))); - - assertThat("[All Media] should be collapsible after drill down", - transform.canCollapse(position, allMedia), is(true)); - assertThat("[All Media] should not be expandable after drill down", - transform.canExpand(position, allMedia), is(false)); + /** + * @see org.pivot4j.transform.impl.AbstractTransformTestCase#getType() + */ + @Override + protected Class getType() { + return DrillExpandPosition.class; + } + + @Test + public void testExpandOnPosition() { + DrillExpandPosition transform = getTransform(); + + PivotModel model = getPivotModel(); + + CellSet cellSet = model.getCellSet(); + assertThat("Unable to execute MDX query : " + getInitialQuery(), + cellSet, is(notNullValue())); + + CellSetAxis axis = cellSet.getAxes().get(1); + Position position = axis.getPositions().get(0); + + Member allMedia = position.getMembers().get(1); + + assertThat( + "Unexpected member at drill position : " + + allMedia.getCaption(), allMedia.getCaption(), + is(equalTo("All Media"))); + + assertThat("[All Media] should not be collapsible initially", + transform.canCollapse(position, allMedia), is(false)); + assertThat("[All Media] should be expandable initially", + transform.canExpand(position, allMedia), is(true)); + + transform.expand(position, allMedia); + + assertThat("Unexpected MDX after drill down : ", model.getCurrentMdx(), + is(equalTo(getTransformedQuery()))); + + assertThat("[All Media] should be collapsible after drill down", + transform.canCollapse(position, allMedia), is(true)); + assertThat("[All Media] should not be expandable after drill down", + transform.canExpand(position, allMedia), is(false)); + + transform.collapse(position, allMedia); + + assertThat("Unexpected MDX after collapse : ", model.getCurrentMdx(), + is(equalTo(getInitialQuery()))); + + assertThat("[All Media] should not be collapsible after collapse", + transform.canCollapse(position, allMedia), is(false)); + assertThat("[All Media] should be expandable after collapse", + transform.canExpand(position, allMedia), is(true)); + } + + @Test + public void testExpandWithSort() { + DrillExpandPosition transform = getTransform(); + + PivotModel model = getPivotModel(); + + CellSet cellSet = model.getCellSet(); + assertThat("Unable to execute MDX query : " + getInitialQuery(), + cellSet, is(notNullValue())); + + CellSetAxis axis = cellSet.getAxes().get(1); + Position position = axis.getPositions().get(0); + + Member allMedia = position.getMembers().get(1); + + assertThat( + "Unexpected member at drill position : " + + allMedia.getCaption(), allMedia.getCaption(), + is(equalTo("All Media"))); + + model.setSorting(true); + model.setTopBottomCount(3); + model.setSortCriteria(SortCriteria.BOTTOMCOUNT); + + model.sort(axis, position); + + assertThat("[All Media] should not be collapsible initially", + transform.canCollapse(position, allMedia), is(false)); + assertThat("[All Media] should be expandable initially", + transform.canExpand(position, allMedia), is(true)); + + transform.expand(position, allMedia); + + assertThat( + "Unexpected MDX after drill down : ", + model.getCurrentMdx(), + is(equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "BottomCount(Union(Union(CrossJoin({[Time].[1997]}, {[Promotion Media].[All Media]}), " + + "CrossJoin({[Time].[1997]}, [Promotion Media].[All Media].Children)), {([Time].[1998], " + + "[Promotion Media].[All Media])}), 3, ([Time].[1997], [Promotion Media].[All Media])) ON ROWS FROM [Sales]"))); + + assertThat("[All Media] should be collapsible after drill down", + transform.canCollapse(position, allMedia), is(true)); + assertThat("[All Media] should not be expandable after drill down", + transform.canExpand(position, allMedia), is(false)); - transform.collapse(position, allMedia); + transform.collapse(position, allMedia); - assertThat( - "Unexpected MDX after collapse : ", - model.getCurrentMdx(), - is(equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} " - + "ON COLUMNS, BottomCount({([Time].[1997], [Promotion Media].[All Media]), " - + "([Time].[1998], [Promotion Media].[All Media])}, 3, ([Time].[1997], [Promotion Media].[All Media])) " - + "ON ROWS FROM [Sales]"))); + assertThat( + "Unexpected MDX after collapse : ", + model.getCurrentMdx(), + is(equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} " + + "ON COLUMNS, BottomCount({([Time].[1997], [Promotion Media].[All Media]), " + + "([Time].[1998], [Promotion Media].[All Media])}, 3, ([Time].[1997], [Promotion Media].[All Media])) " + + "ON ROWS FROM [Sales]"))); - assertThat("[All Media] should not be collapsible after collapse", - transform.canCollapse(position, allMedia), is(false)); - assertThat("[All Media] should be expandable after collapse", - transform.canExpand(position, allMedia), is(true)); - } + assertThat("[All Media] should not be collapsible after collapse", + transform.canCollapse(position, allMedia), is(false)); + assertThat("[All Media] should be expandable after collapse", + transform.canExpand(position, allMedia), is(true)); + } } diff --git a/pivot4j-core/src/test/java/org/pivot4j/transform/impl/DrillReplaceImplIT.java b/pivot4j-core/src/test/java/org/pivot4j/transform/impl/DrillReplaceImplIT.java index 0c1965cd..0799668f 100644 --- a/pivot4j-core/src/test/java/org/pivot4j/transform/impl/DrillReplaceImplIT.java +++ b/pivot4j-core/src/test/java/org/pivot4j/transform/impl/DrillReplaceImplIT.java @@ -24,77 +24,78 @@ public class DrillReplaceImplIT extends AbstractTransformTestCase { - private String initialQuery = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales]"; - - /** - * @return the initialQuery - * @see org.pivot4j.transform.impl.AbstractTransformTestCase#getInitialQuery() - */ - protected String getInitialQuery() { - return initialQuery; - } - - /** - * @see org.pivot4j.transform.impl.AbstractTransformTestCase#getType() - */ - @Override - protected Class getType() { - return DrillReplace.class; - } - - @Test - public void testTransform() { - DrillReplace transform = getTransform(); - - CellSet cellSet = getPivotModel().getCellSet(); - CellSetAxis axis = cellSet.getAxes().get(1); - - Position position = axis.getPositions().get(0); - List members = position.getMembers(); - - Member allMedia = members.get(0); - Hierarchy hierarchy = allMedia.getHierarchy(); - - assertThat( - "Should be able to drill down on [Promotion Media].[All Media]", - transform.canDrillDown(allMedia), is(true)); - assertThat( - "Drill up on [Promotion Media] hierarchy should not be possible", - transform.canDrillUp(hierarchy), is(false)); - - transform.drillDown(allMedia); - - assertThat( - "Unexpected MDX query after drill down on " - + allMedia.getUniqueName(), - getPivotModel().getCurrentMdx(), - is(equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "CrossJoin([Promotion Media].[All Media].Children, {[Product].[All Products]}) ON ROWS " - + "FROM [Sales]"))); - - cellSet = getPivotModel().getCellSet(); - - axis = cellSet.getAxes().get(1); - - position = axis.getPositions().get(0); - members = position.getMembers(); - - Member bulkMail = members.get(0); - - assertThat( - "Drill down on [Promotion Media].[Bulk Mail] member should not be possible", - transform.canDrillDown(bulkMail), is(false)); - assertThat("Should be able to drill up on [Promotion Media] hierarchy", - transform.canDrillUp(hierarchy), is(true)); - - transform.drillUp(hierarchy); - - assertThat( - "Unexpected MDX query after drill down up " - + hierarchy.getUniqueName(), getPivotModel() - .getCurrentMdx(), is(equalTo(getInitialQuery()))); - - cellSet = getPivotModel().getCellSet(); - } + private String initialQuery = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales]"; + + /** + * @return the initialQuery + * @see + * org.pivot4j.transform.impl.AbstractTransformTestCase#getInitialQuery() + */ + protected String getInitialQuery() { + return initialQuery; + } + + /** + * @see org.pivot4j.transform.impl.AbstractTransformTestCase#getType() + */ + @Override + protected Class getType() { + return DrillReplace.class; + } + + @Test + public void testTransform() { + DrillReplace transform = getTransform(); + + CellSet cellSet = getPivotModel().getCellSet(); + CellSetAxis axis = cellSet.getAxes().get(1); + + Position position = axis.getPositions().get(0); + List members = position.getMembers(); + + Member allMedia = members.get(0); + Hierarchy hierarchy = allMedia.getHierarchy(); + + assertThat( + "Should be able to drill down on [Promotion Media].[All Media]", + transform.canDrillDown(allMedia), is(true)); + assertThat( + "Drill up on [Promotion Media] hierarchy should not be possible", + transform.canDrillUp(hierarchy), is(false)); + + transform.drillDown(allMedia); + + assertThat( + "Unexpected MDX query after drill down on " + + allMedia.getUniqueName(), + getPivotModel().getCurrentMdx(), + is(equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "CrossJoin([Promotion Media].[All Media].Children, {[Product].[All Products]}) ON ROWS " + + "FROM [Sales]"))); + + cellSet = getPivotModel().getCellSet(); + + axis = cellSet.getAxes().get(1); + + position = axis.getPositions().get(0); + members = position.getMembers(); + + Member bulkMail = members.get(0); + + assertThat( + "Drill down on [Promotion Media].[Bulk Mail] member should not be possible", + transform.canDrillDown(bulkMail), is(false)); + assertThat("Should be able to drill up on [Promotion Media] hierarchy", + transform.canDrillUp(hierarchy), is(true)); + + transform.drillUp(hierarchy); + + assertThat( + "Unexpected MDX query after drill down up " + + hierarchy.getUniqueName(), getPivotModel() + .getCurrentMdx(), is(equalTo(getInitialQuery()))); + + cellSet = getPivotModel().getCellSet(); + } } diff --git a/pivot4j-core/src/test/java/org/pivot4j/transform/impl/NonEmptyImplIT.java b/pivot4j-core/src/test/java/org/pivot4j/transform/impl/NonEmptyImplIT.java index 6573ecc5..27211ae8 100644 --- a/pivot4j-core/src/test/java/org/pivot4j/transform/impl/NonEmptyImplIT.java +++ b/pivot4j-core/src/test/java/org/pivot4j/transform/impl/NonEmptyImplIT.java @@ -17,51 +17,52 @@ public class NonEmptyImplIT extends AbstractTransformTestCase { - private String initialQuery = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales]"; + private String initialQuery = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales]"; - /** - * @return the initialQuery - * @see org.pivot4j.transform.impl.AbstractTransformTestCase#getInitialQuery() - */ - protected String getInitialQuery() { - return initialQuery; - } + /** + * @return the initialQuery + * @see + * org.pivot4j.transform.impl.AbstractTransformTestCase#getInitialQuery() + */ + protected String getInitialQuery() { + return initialQuery; + } - /** - * @see org.pivot4j.transform.impl.AbstractTransformTestCase#getType() - */ - @Override - protected Class getType() { - return NonEmpty.class; - } + /** + * @see org.pivot4j.transform.impl.AbstractTransformTestCase#getType() + */ + @Override + protected Class getType() { + return NonEmpty.class; + } - @Test - public void testTransform() { - NonEmpty transform = getTransform(); + @Test + public void testTransform() { + NonEmpty transform = getTransform(); - assertThat("Initial query does not include NON EMPTY statement", - transform.isNonEmpty(), is(false)); + assertThat("Initial query does not include NON EMPTY statement", + transform.isNonEmpty(), is(false)); - transform.setNonEmpty(true); + transform.setNonEmpty(true); - assertThat("Query does contain NON EMPTY statement", - transform.isNonEmpty(), is(true)); - assertThat( - "Unexpected MDX query after set NON EMPTY statement", - getPivotModel().getCurrentMdx(), - is(equalTo("SELECT NON EMPTY {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "NON EMPTY {([Promotion Media].[All Media], [Product].[All Products])} ON ROWS " - + "FROM [Sales]"))); + assertThat("Query does contain NON EMPTY statement", + transform.isNonEmpty(), is(true)); + assertThat( + "Unexpected MDX query after set NON EMPTY statement", + getPivotModel().getCurrentMdx(), + is(equalTo("SELECT NON EMPTY {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "NON EMPTY {([Promotion Media].[All Media], [Product].[All Products])} ON ROWS " + + "FROM [Sales]"))); - getPivotModel().getCellSet(); + getPivotModel().getCellSet(); - transform.setNonEmpty(false); + transform.setNonEmpty(false); - assertThat("Query does not contain NON EMPTY statement", - transform.isNonEmpty(), is(false)); + assertThat("Query does not contain NON EMPTY statement", + transform.isNonEmpty(), is(false)); - assertThat("Unexpected MDX query after removing NON EMPTY statement", - getPivotModel().getCurrentMdx(), is(equalTo(getInitialQuery()))); - } + assertThat("Unexpected MDX query after removing NON EMPTY statement", + getPivotModel().getCurrentMdx(), is(equalTo(getInitialQuery()))); + } } diff --git a/pivot4j-core/src/test/java/org/pivot4j/transform/impl/PlaceHierarchiesOnAxesImplIT.java b/pivot4j-core/src/test/java/org/pivot4j/transform/impl/PlaceHierarchiesOnAxesImplIT.java index 6425bb11..94741939 100644 --- a/pivot4j-core/src/test/java/org/pivot4j/transform/impl/PlaceHierarchiesOnAxesImplIT.java +++ b/pivot4j-core/src/test/java/org/pivot4j/transform/impl/PlaceHierarchiesOnAxesImplIT.java @@ -22,236 +22,237 @@ public class PlaceHierarchiesOnAxesImplIT extends AbstractTransformTestCase { - private String initialQuery = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "Hierarchize(Union({[Product].[All Products]}, [Product].[All Products].Children)) ON ROWS FROM [Sales]"; + private String initialQuery = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "Hierarchize(Union({[Product].[All Products]}, [Product].[All Products].Children)) ON ROWS FROM [Sales]"; - /** - * @return the initialQuery - * @see org.pivot4j.transform.impl.AbstractTransformTestCase#getInitialQuery() - */ - protected String getInitialQuery() { - return initialQuery; - } + /** + * @return the initialQuery + * @see + * org.pivot4j.transform.impl.AbstractTransformTestCase#getInitialQuery() + */ + protected String getInitialQuery() { + return initialQuery; + } - /** - * @see org.pivot4j.transform.impl.AbstractTransformTestCase#getType() - */ - @Override - protected Class getType() { - return PlaceHierarchiesOnAxes.class; - } + /** + * @see org.pivot4j.transform.impl.AbstractTransformTestCase#getType() + */ + @Override + protected Class getType() { + return PlaceHierarchiesOnAxes.class; + } - @Test - public void testPlaceHierarchies() { - PlaceHierarchiesOnAxes transform = getTransform(); + @Test + public void testPlaceHierarchies() { + PlaceHierarchiesOnAxes transform = getTransform(); - Cube cube = getPivotModel().getCube(); + Cube cube = getPivotModel().getCube(); - Hierarchy promotionMedia = cube.getHierarchies().get("Promotion Media"); - Hierarchy product = cube.getHierarchies().get("Product"); + Hierarchy promotionMedia = cube.getHierarchies().get("Promotion Media"); + Hierarchy product = cube.getHierarchies().get("Product"); - List hierarchies = new ArrayList(2); - hierarchies.add(promotionMedia); - hierarchies.add(product); + List hierarchies = new ArrayList(2); + hierarchies.add(promotionMedia); + hierarchies.add(product); - transform.placeHierarchies(Axis.ROWS, hierarchies, false); + transform.placeHierarchies(Axis.ROWS, hierarchies, false); - assertThat("Unexpected MDX query", getPivotModel().getCurrentMdx(), - is(equalTo( - "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "CrossJoin({[Promotion Media].[All Media]}, {[Product].[All Products], [Product].[Drink], " - + "[Product].[Food], [Product].[Non-Consumable]}) ON ROWS FROM [Sales]"))); + assertThat("Unexpected MDX query", getPivotModel().getCurrentMdx(), + is(equalTo( + "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "CrossJoin({[Promotion Media].[All Media]}, {[Product].[All Products], [Product].[Drink], " + + "[Product].[Food], [Product].[Non-Consumable]}) ON ROWS FROM [Sales]"))); - getPivotModel().getCellSet(); - } + getPivotModel().getCellSet(); + } - @Test - public void testExpandAllMembers() { - PlaceHierarchiesOnAxes transform = getTransform(); + @Test + public void testExpandAllMembers() { + PlaceHierarchiesOnAxes transform = getTransform(); - Cube cube = getPivotModel().getCube(); + Cube cube = getPivotModel().getCube(); - Hierarchy promotionMedia = cube.getHierarchies().get("Promotion Media"); - Hierarchy product = cube.getHierarchies().get("Product"); + Hierarchy promotionMedia = cube.getHierarchies().get("Promotion Media"); + Hierarchy product = cube.getHierarchies().get("Product"); - List hierarchies = new ArrayList(2); - hierarchies.add(promotionMedia); - hierarchies.add(product); + List hierarchies = new ArrayList(2); + hierarchies.add(promotionMedia); + hierarchies.add(product); - transform.placeHierarchies(Axis.ROWS, hierarchies, true); + transform.placeHierarchies(Axis.ROWS, hierarchies, true); - assertThat("Unexpected MDX query after set hierarchies on axis", getPivotModel().getCurrentMdx(), is( - equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "CrossJoin(Union({[Promotion Media].[All Media]}, [Promotion Media].[All Media].Children), " - + "{[Product].[All Products], [Product].[Drink], [Product].[Food], [Product].[Non-Consumable]}) ON ROWS FROM [Sales]"))); + assertThat("Unexpected MDX query after set hierarchies on axis", getPivotModel().getCurrentMdx(), is( + equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "CrossJoin(Union({[Promotion Media].[All Media]}, [Promotion Media].[All Media].Children), " + + "{[Product].[All Products], [Product].[Drink], [Product].[Food], [Product].[Non-Consumable]}) ON ROWS FROM [Sales]"))); - getPivotModel().getCellSet(); - } + getPivotModel().getCellSet(); + } - @Test - public void testExpandAllMembersExcludingAll() { - PlaceHierarchiesOnAxes transform = getTransform(); + @Test + public void testExpandAllMembersExcludingAll() { + PlaceHierarchiesOnAxes transform = getTransform(); - Cube cube = getPivotModel().getCube(); + Cube cube = getPivotModel().getCube(); - Hierarchy promotionMedia = cube.getHierarchies().get("Promotion Media"); - Hierarchy product = cube.getHierarchies().get("Product"); + Hierarchy promotionMedia = cube.getHierarchies().get("Promotion Media"); + Hierarchy product = cube.getHierarchies().get("Product"); - List hierarchies = new ArrayList(2); - hierarchies.add(promotionMedia); - hierarchies.add(product); + List hierarchies = new ArrayList(2); + hierarchies.add(promotionMedia); + hierarchies.add(product); - transform.placeHierarchies(Axis.ROWS, hierarchies, true, false); + transform.placeHierarchies(Axis.ROWS, hierarchies, true, false); - assertThat("Unexpected MDX query after set hierarchies on axis", getPivotModel().getCurrentMdx(), is( - equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "CrossJoin([Promotion Media].[All Media].Children, " - + "{[Product].[All Products], [Product].[Drink], [Product].[Food], [Product].[Non-Consumable]}) ON ROWS FROM [Sales]"))); + assertThat("Unexpected MDX query after set hierarchies on axis", getPivotModel().getCurrentMdx(), is( + equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "CrossJoin([Promotion Media].[All Media].Children, " + + "{[Product].[All Products], [Product].[Drink], [Product].[Food], [Product].[Non-Consumable]}) ON ROWS FROM [Sales]"))); - getPivotModel().getCellSet(); - } + getPivotModel().getCellSet(); + } - @Test - public void testAddHierarchyAtIndexMinusOne() { - PlaceHierarchiesOnAxes transform = getTransform(); + @Test + public void testAddHierarchyAtIndexMinusOne() { + PlaceHierarchiesOnAxes transform = getTransform(); - Cube cube = getPivotModel().getCube(); + Cube cube = getPivotModel().getCube(); - Hierarchy gender = cube.getHierarchies().get("Gender"); + Hierarchy gender = cube.getHierarchies().get("Gender"); - transform.addHierarchy(Axis.ROWS, gender, false, -1); + transform.addHierarchy(Axis.ROWS, gender, false, -1); - assertThat("Unexpected MDX query after adding a new hierarchy", getPivotModel().getCurrentMdx(), - is(equalTo( - "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS" - + ", CrossJoin({[Product].[All Products], [Product].[Drink], [Product].[Food], [Product].[Non-Consumable]}, " - + "{[Gender].[All Gender]}) ON ROWS FROM [Sales]"))); + assertThat("Unexpected MDX query after adding a new hierarchy", getPivotModel().getCurrentMdx(), + is(equalTo( + "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS" + + ", CrossJoin({[Product].[All Products], [Product].[Drink], [Product].[Food], [Product].[Non-Consumable]}, " + + "{[Gender].[All Gender]}) ON ROWS FROM [Sales]"))); - getPivotModel().getCellSet(); - } + getPivotModel().getCellSet(); + } - @Test - public void testAddHierarchyAtIndexTwo() { - PlaceHierarchiesOnAxes transform = getTransform(); + @Test + public void testAddHierarchyAtIndexTwo() { + PlaceHierarchiesOnAxes transform = getTransform(); - Cube cube = getPivotModel().getCube(); + Cube cube = getPivotModel().getCube(); - Hierarchy gender = cube.getHierarchies().get("Gender"); + Hierarchy gender = cube.getHierarchies().get("Gender"); - transform.addHierarchy(Axis.ROWS, gender, false, 2); + transform.addHierarchy(Axis.ROWS, gender, false, 2); - assertThat("Unexpected MDX query after adding a new hierarchy", getPivotModel().getCurrentMdx(), - is(equalTo( - "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS" - + ", CrossJoin({[Product].[All Products], [Product].[Drink], [Product].[Food], [Product].[Non-Consumable]}, " - + "{[Gender].[All Gender]}) ON ROWS FROM [Sales]"))); + assertThat("Unexpected MDX query after adding a new hierarchy", getPivotModel().getCurrentMdx(), + is(equalTo( + "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS" + + ", CrossJoin({[Product].[All Products], [Product].[Drink], [Product].[Food], [Product].[Non-Consumable]}, " + + "{[Gender].[All Gender]}) ON ROWS FROM [Sales]"))); - getPivotModel().getCellSet(); - } + getPivotModel().getCellSet(); + } - @Test - public void testAddHierarchyAtIndexZero() { - PlaceHierarchiesOnAxes transform = getTransform(); + @Test + public void testAddHierarchyAtIndexZero() { + PlaceHierarchiesOnAxes transform = getTransform(); - Cube cube = getPivotModel().getCube(); + Cube cube = getPivotModel().getCube(); - Hierarchy gender = cube.getHierarchies().get("Gender"); + Hierarchy gender = cube.getHierarchies().get("Gender"); - transform.addHierarchy(Axis.ROWS, gender, false, 0); + transform.addHierarchy(Axis.ROWS, gender, false, 0); - assertThat("Unexpected MDX query after adding a new hierarchy", getPivotModel().getCurrentMdx(), - is(equalTo( - "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "CrossJoin({[Gender].[All Gender]}, {[Product].[All Products], [Product].[Drink], [Product].[Food], " - + "[Product].[Non-Consumable]}) ON ROWS FROM [Sales]"))); + assertThat("Unexpected MDX query after adding a new hierarchy", getPivotModel().getCurrentMdx(), + is(equalTo( + "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "CrossJoin({[Gender].[All Gender]}, {[Product].[All Products], [Product].[Drink], [Product].[Food], " + + "[Product].[Non-Consumable]}) ON ROWS FROM [Sales]"))); - getPivotModel().getCellSet(); - } + getPivotModel().getCellSet(); + } - @Test - public void testMoveHierarchy() { - String query = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "CrossJoin(Union({[Promotion Media].[All Media]}, [Promotion Media].[All Media].Children), " - + "{[Product].[All Products], [Product].[Drink], [Product].[Food], [Product].[Non-Consumable]}) ON ROWS FROM [Sales]"; + @Test + public void testMoveHierarchy() { + String query = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "CrossJoin(Union({[Promotion Media].[All Media]}, [Promotion Media].[All Media].Children), " + + "{[Product].[All Products], [Product].[Drink], [Product].[Food], [Product].[Non-Consumable]}) ON ROWS FROM [Sales]"; - getPivotModel().setMdx(query); + getPivotModel().setMdx(query); - PlaceHierarchiesOnAxes transform = getTransform(); + PlaceHierarchiesOnAxes transform = getTransform(); - Cube cube = getPivotModel().getCube(); + Cube cube = getPivotModel().getCube(); - Hierarchy product = cube.getHierarchies().get("Product"); + Hierarchy product = cube.getHierarchies().get("Product"); - transform.moveHierarchy(Axis.ROWS, product, 0); + transform.moveHierarchy(Axis.ROWS, product, 0); - assertThat(getPivotModel().getCurrentMdx(), - is(equalTo( - "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "CrossJoin({[Product].[All Products], [Product].[Drink], [Product].[Food], [Product].[Non-Consumable]}, " - + "{[Promotion Media].[All Media], [Promotion Media].[Bulk Mail], [Promotion Media].[Cash Register Handout], " - + "[Promotion Media].[Daily Paper], [Promotion Media].[Daily Paper, Radio], [Promotion Media].[Daily Paper, Radio, TV], " - + "[Promotion Media].[In-Store Coupon], [Promotion Media].[No Media], [Promotion Media].[Product Attachment], " - + "[Promotion Media].[Radio], [Promotion Media].[Street Handout], [Promotion Media].[Sunday Paper], " - + "[Promotion Media].[Sunday Paper, Radio], [Promotion Media].[Sunday Paper, Radio, TV], " - + "[Promotion Media].[TV]}) ON ROWS FROM [Sales]"))); + assertThat(getPivotModel().getCurrentMdx(), + is(equalTo( + "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "CrossJoin({[Product].[All Products], [Product].[Drink], [Product].[Food], [Product].[Non-Consumable]}, " + + "{[Promotion Media].[All Media], [Promotion Media].[Bulk Mail], [Promotion Media].[Cash Register Handout], " + + "[Promotion Media].[Daily Paper], [Promotion Media].[Daily Paper, Radio], [Promotion Media].[Daily Paper, Radio, TV], " + + "[Promotion Media].[In-Store Coupon], [Promotion Media].[No Media], [Promotion Media].[Product Attachment], " + + "[Promotion Media].[Radio], [Promotion Media].[Street Handout], [Promotion Media].[Sunday Paper], " + + "[Promotion Media].[Sunday Paper, Radio], [Promotion Media].[Sunday Paper, Radio, TV], " + + "[Promotion Media].[TV]}) ON ROWS FROM [Sales]"))); - getPivotModel().getCellSet(); - } + getPivotModel().getCellSet(); + } - @Test - public void testRemoveHierarchy() { - String query = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "CrossJoin(Union({[Promotion Media].[All Media]}, [Promotion Media].[All Media].Children), " - + "{[Product].[All Products], [Product].[Drink], [Product].[Food], [Product].[Non-Consumable]}) ON ROWS FROM [Sales]"; + @Test + public void testRemoveHierarchy() { + String query = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "CrossJoin(Union({[Promotion Media].[All Media]}, [Promotion Media].[All Media].Children), " + + "{[Product].[All Products], [Product].[Drink], [Product].[Food], [Product].[Non-Consumable]}) ON ROWS FROM [Sales]"; - getPivotModel().setMdx(query); + getPivotModel().setMdx(query); - PlaceHierarchiesOnAxes transform = getTransform(); + PlaceHierarchiesOnAxes transform = getTransform(); - Cube cube = getPivotModel().getCube(); + Cube cube = getPivotModel().getCube(); - Hierarchy product = cube.getHierarchies().get("Product"); + Hierarchy product = cube.getHierarchies().get("Product"); - transform.removeHierarchy(Axis.ROWS, product); + transform.removeHierarchy(Axis.ROWS, product); - assertThat(getPivotModel().getCurrentMdx(), - is(equalTo( - "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "{[Promotion Media].[All Media], [Promotion Media].[Bulk Mail], [Promotion Media].[Cash Register Handout], " - + "[Promotion Media].[Daily Paper], [Promotion Media].[Daily Paper, Radio], [Promotion Media].[Daily Paper, Radio, TV], " - + "[Promotion Media].[In-Store Coupon], [Promotion Media].[No Media], [Promotion Media].[Product Attachment], " - + "[Promotion Media].[Radio], [Promotion Media].[Street Handout], [Promotion Media].[Sunday Paper], " - + "[Promotion Media].[Sunday Paper, Radio], [Promotion Media].[Sunday Paper, Radio, TV], " - + "[Promotion Media].[TV]} ON ROWS FROM [Sales]"))); + assertThat(getPivotModel().getCurrentMdx(), + is(equalTo( + "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "{[Promotion Media].[All Media], [Promotion Media].[Bulk Mail], [Promotion Media].[Cash Register Handout], " + + "[Promotion Media].[Daily Paper], [Promotion Media].[Daily Paper, Radio], [Promotion Media].[Daily Paper, Radio, TV], " + + "[Promotion Media].[In-Store Coupon], [Promotion Media].[No Media], [Promotion Media].[Product Attachment], " + + "[Promotion Media].[Radio], [Promotion Media].[Street Handout], [Promotion Media].[Sunday Paper], " + + "[Promotion Media].[Sunday Paper, Radio], [Promotion Media].[Sunday Paper, Radio, TV], " + + "[Promotion Media].[TV]} ON ROWS FROM [Sales]"))); - getPivotModel().getCellSet(); - } + getPivotModel().getCellSet(); + } - @Test - public void testFindVisibleHierarchies() { - String query = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "CrossJoin(Union({[Promotion Media].[All Media]}, [Promotion Media].[All Media].Children), " - + "{[Product].[All Products], [Product].[Drink], [Product].[Food], [Product].[Non-Consumable]}) ON ROWS FROM [Sales]"; + @Test + public void testFindVisibleHierarchies() { + String query = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "CrossJoin(Union({[Promotion Media].[All Media]}, [Promotion Media].[All Media].Children), " + + "{[Product].[All Products], [Product].[Drink], [Product].[Food], [Product].[Non-Consumable]}) ON ROWS FROM [Sales]"; - getPivotModel().setMdx(query); + getPivotModel().setMdx(query); - PlaceHierarchiesOnAxes transform = getTransform(); + PlaceHierarchiesOnAxes transform = getTransform(); - List columnHierarhies = transform.findVisibleHierarchies(Axis.COLUMNS); - List rowHierarhies = transform.findVisibleHierarchies(Axis.ROWS); + List columnHierarhies = transform.findVisibleHierarchies(Axis.COLUMNS); + List rowHierarhies = transform.findVisibleHierarchies(Axis.ROWS); - assertThat("Hierarchy list on the column axis should not be null", columnHierarhies, is(notNullValue())); - assertThat("Number of hierarchy on the column axis should be 1", columnHierarhies.size(), is(equalTo(1))); + assertThat("Hierarchy list on the column axis should not be null", columnHierarhies, is(notNullValue())); + assertThat("Number of hierarchy on the column axis should be 1", columnHierarhies.size(), is(equalTo(1))); - assertThat("Wrong name for the first hierarchy on the column axis", columnHierarhies.get(0).getName(), - is(equalTo("Measures"))); + assertThat("Wrong name for the first hierarchy on the column axis", columnHierarhies.get(0).getName(), + is(equalTo("Measures"))); - assertThat("Hierarchy list on the row axis should not be null", rowHierarhies, is(notNullValue())); - assertThat("Number of hierarchies on the column axis should be 2", rowHierarhies.size(), is(equalTo(2))); + assertThat("Hierarchy list on the row axis should not be null", rowHierarhies, is(notNullValue())); + assertThat("Number of hierarchies on the column axis should be 2", rowHierarhies.size(), is(equalTo(2))); - assertThat("Wrong name for the first hierarchy on the row axis", rowHierarhies.get(0).getName(), - is(equalTo("Promotion Media"))); - assertThat("Wrong name for the seconde hierarchy on the row axis", rowHierarhies.get(1).getName(), - is(equalTo("Product"))); - } + assertThat("Wrong name for the first hierarchy on the row axis", rowHierarhies.get(0).getName(), + is(equalTo("Promotion Media"))); + assertThat("Wrong name for the seconde hierarchy on the row axis", rowHierarhies.get(1).getName(), + is(equalTo("Product"))); + } } diff --git a/pivot4j-core/src/test/java/org/pivot4j/transform/impl/PlaceLevelsOnAxesImplIT.java b/pivot4j-core/src/test/java/org/pivot4j/transform/impl/PlaceLevelsOnAxesImplIT.java index 40651c30..6af458c9 100644 --- a/pivot4j-core/src/test/java/org/pivot4j/transform/impl/PlaceLevelsOnAxesImplIT.java +++ b/pivot4j-core/src/test/java/org/pivot4j/transform/impl/PlaceLevelsOnAxesImplIT.java @@ -25,240 +25,241 @@ import org.pivot4j.transform.PlaceLevelsOnAxes; public class PlaceLevelsOnAxesImplIT extends - AbstractTransformTestCase { - - private String initialQuery = "select {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS," - + " Hierarchize(Union(Union(Union(Crossjoin({[Promotion Media].[All Media]}, {[Product].[All Products]}), " - + "Crossjoin({[Promotion Media].[All Media]}, [Product].[All Products].Children)), Crossjoin({[Promotion Media].[All Media]}, " - + "[Product].[Drink].Children)), Crossjoin({[Promotion Media].[All Media]}, [Product].[Drink].[Beverages].Children))) ON ROWS " - + "from [Sales] where [Time].[1997]"; - - /** - * @return the initialQuery - * @see org.pivot4j.transform.impl.AbstractTransformTestCase#getInitialQuery() - */ - protected String getInitialQuery() { - return initialQuery; - } - - /** - * @see org.pivot4j.transform.impl.AbstractTransformTestCase#getType() - */ - @Override - protected Class getType() { - return PlaceLevelsOnAxes.class; - } - - @Test - public void testFindVisibleLevels() throws OlapException { - PlaceLevelsOnAxes transform = getTransform(); - - Cube cube = getPivotModel().getCube(); - - Hierarchy promotionMedia = cube.getHierarchies().get("Promotion Media"); - Hierarchy product = cube.getHierarchies().get("Product"); - - List firstLevels = transform.findVisibleLevels(promotionMedia); - assertThat( - "The number of visible levels in [Promotion Media] hierarchy should be 1", - firstLevels.size(), is(equalTo(1))); - assertThat( - "The first level of the hierarchy should be [Promotion Media].[(All)]", - promotionMedia.getLevels().get(0).getUniqueName(), - is(equalTo(firstLevels.get(0).getUniqueName()))); - - List allLevels = transform.findVisibleLevels(Axis.ROWS); - - assertThat("Visible levels should not be empty", allLevels.isEmpty(), - is(false)); - assertThat("The number of visible levels should be 5", - allLevels.size(), is(equalTo(5))); - assertThat( - "The first level of the axis should be [Promotion Media].[(All)]", - promotionMedia.getLevels().get(0).getUniqueName(), - is(equalTo(allLevels.get(0).getUniqueName()))); - - assertThat("The second level of the axis should be [Product].[(All)]", - product.getLevels().get(0).getUniqueName(), - is(equalTo(allLevels.get(1).getUniqueName()))); - assertThat( - "The third level of the axis should be [Product].[Product Family]", - product.getLevels().get(1).getUniqueName(), - is(equalTo(allLevels.get(2).getUniqueName()))); - assertThat( - "The fourth level of the axis should be [Product].[Product Department]", - product.getLevels().get(2).getUniqueName(), - is(equalTo(allLevels.get(3).getUniqueName()))); - assertThat( - "The fourth level of the axis should be [Product].[Product Category]", - product.getLevels().get(3).getUniqueName(), - is(equalTo(allLevels.get(4).getUniqueName()))); - } - - @Test - public void testAddLevelOnExisiingHierarchy() throws OlapException { - PlaceLevelsOnAxes transform = getTransform(); - - Cube cube = getPivotModel().getCube(); - - Hierarchy promotionMedia = cube.getHierarchies().get("Promotion Media"); - Level level = promotionMedia.getLevels().get(1); - - transform.addLevel(Axis.ROWS, level, -1); - - assertThat( - "Unexpected MDX query", - getPivotModel().getCurrentMdx(), - is(equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "CrossJoin({[Promotion Media].[All Media], [Promotion Media].[Bulk Mail], [Promotion Media].[Cash Register Handout], " - + "[Promotion Media].[Daily Paper], [Promotion Media].[Daily Paper, Radio], " - + "[Promotion Media].[Daily Paper, Radio, TV], [Promotion Media].[In-Store Coupon], [Promotion Media].[No Media], " - + "[Promotion Media].[Product Attachment], [Promotion Media].[Radio], [Promotion Media].[Street Handout], " - + "[Promotion Media].[Sunday Paper], [Promotion Media].[Sunday Paper, Radio], " - + "[Promotion Media].[Sunday Paper, Radio, TV], [Promotion Media].[TV]}, {[Product].[All Products], " - + "[Product].[Drink], [Product].[Drink].[Alcoholic Beverages], [Product].[Drink].[Beverages], " - + "[Product].[Drink].[Beverages].[Carbonated Beverages], [Product].[Drink].[Beverages].[Drinks], " - + "[Product].[Drink].[Beverages].[Hot Beverages], [Product].[Drink].[Beverages].[Pure Juice Beverages], " - + "[Product].[Drink].[Dairy], [Product].[Food], [Product].[Non-Consumable]}) ON ROWS " - + "FROM [Sales] WHERE [Time].[1997]"))); - } - - @Test - public void testAddLevelAtTheBeginning() throws OlapException { - PlaceLevelsOnAxes transform = getTransform(); - - Cube cube = getPivotModel().getCube(); - - Hierarchy gender = cube.getHierarchies().get("Gender"); - Level level = gender.getLevels().get(1); - - transform.addLevel(Axis.ROWS, level, 0); - - assertThat( - "Unexpected MDX query", - getPivotModel().getCurrentMdx(), - is(equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "CrossJoin({[Gender].[F], [Gender].[M]}, CrossJoin({[Promotion Media].[All Media]}, {[Product].[All Products], " - + "[Product].[Drink], [Product].[Drink].[Alcoholic Beverages], [Product].[Drink].[Beverages], " - + "[Product].[Drink].[Beverages].[Carbonated Beverages], [Product].[Drink].[Beverages].[Drinks], " - + "[Product].[Drink].[Beverages].[Hot Beverages], [Product].[Drink].[Beverages].[Pure Juice Beverages], " - + "[Product].[Drink].[Dairy], [Product].[Food], [Product].[Non-Consumable]})) ON ROWS " - + "FROM [Sales] WHERE [Time].[1997]"))); - } - - @Test - public void testPlaceLevels() throws OlapException { - PlaceLevelsOnAxes transform = getTransform(); - - Cube cube = getPivotModel().getCube(); - - Hierarchy gender = cube.getHierarchies().get("Gender"); - Hierarchy store = cube.getHierarchies().get("Store"); - - List levels = new ArrayList(); - levels.add(gender.getLevels().get(0)); - levels.add(store.getLevels().get(1)); - - transform.placeLevels(Axis.ROWS, levels); - - assertThat( - "Unexpected MDX query", - getPivotModel().getCurrentMdx(), - is(equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "CrossJoin({[Gender].[All Gender]}, {[Store].[Canada], [Store].[Mexico], [Store].[USA]}) ON ROWS " - + "FROM [Sales] WHERE [Time].[1997]"))); - } - - @Test - public void testAddLevelAtTheMiddle() throws OlapException { - PlaceLevelsOnAxes transform = getTransform(); - - Cube cube = getPivotModel().getCube(); - - Hierarchy gender = cube.getHierarchies().get("Gender"); - Level level = gender.getLevels().get(1); - - transform.addLevel(Axis.ROWS, level, 1); - - assertThat( - "Unexpected MDX query", - getPivotModel().getCurrentMdx(), - is(equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "CrossJoin({[Promotion Media].[All Media]}, CrossJoin({[Gender].[F], [Gender].[M]}, " - + "{[Product].[All Products], [Product].[Drink], [Product].[Drink].[Alcoholic Beverages], " - + "[Product].[Drink].[Beverages], [Product].[Drink].[Beverages].[Carbonated Beverages], " - + "[Product].[Drink].[Beverages].[Drinks], [Product].[Drink].[Beverages].[Hot Beverages], " - + "[Product].[Drink].[Beverages].[Pure Juice Beverages], [Product].[Drink].[Dairy], " - + "[Product].[Food], [Product].[Non-Consumable]})) ON ROWS FROM [Sales] WHERE [Time].[1997]"))); - } - - @Test - public void testAddLevelAtTheEnd() throws OlapException { - PlaceLevelsOnAxes transform = getTransform(); - - Cube cube = getPivotModel().getCube(); - - Hierarchy gender = cube.getHierarchies().get("Gender"); - Level level = gender.getLevels().get(1); - - transform.addLevel(Axis.ROWS, level, 2); - - assertThat( - "Unexpected MDX query", - getPivotModel().getCurrentMdx(), - is(equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "CrossJoin({[Promotion Media].[All Media]}, CrossJoin({[Product].[All Products], [Product].[Drink], " - + "[Product].[Drink].[Alcoholic Beverages], [Product].[Drink].[Beverages], [Product].[Drink].[Beverages].[Carbonated Beverages], " - + "[Product].[Drink].[Beverages].[Drinks], [Product].[Drink].[Beverages].[Hot Beverages], " - + "[Product].[Drink].[Beverages].[Pure Juice Beverages], [Product].[Drink].[Dairy], [Product].[Food], " - + "[Product].[Non-Consumable]}, {[Gender].[F], [Gender].[M]})) ON ROWS FROM [Sales] WHERE [Time].[1997]"))); - } - - @Test - public void testRemoveLevel() throws OlapException { - PlaceLevelsOnAxes transform = getTransform(); - - Cube cube = getPivotModel().getCube(); - - Hierarchy product = cube.getHierarchies().get("Product"); - - Level level = product.getLevels().get("Product Department"); - - transform.removeLevel(Axis.ROWS, level); - - assertThat( - "Unexpected MDX query", - getPivotModel().getCurrentMdx(), - is(equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "CrossJoin({[Promotion Media].[All Media]}, {[Product].[All Products], [Product].[Drink], " - + "[Product].[Drink].[Beverages].[Carbonated Beverages], [Product].[Drink].[Beverages].[Drinks], " - + "[Product].[Drink].[Beverages].[Hot Beverages], [Product].[Drink].[Beverages].[Pure Juice Beverages], " - + "[Product].[Food], [Product].[Non-Consumable]}) ON ROWS FROM [Sales] WHERE [Time].[1997]"))); - } - - @Test - public void testRemoveLevelFromCrossJoinedAxis() throws OlapException { - PlaceLevelsOnAxes transform = getTransform(); - - PivotModel model = getPivotModel(); - model.setMdx("SELECT {[Measures].[Unit Sales]} ON COLUMNS, Union(Union({([Product].[All Products], [Gender].[All Gender])}, " - + "Union(Union(CrossJoin({[Product].[Food]}, {[Gender].[All Gender]}), CrossJoin({[Product].[Food]}, {[Gender].[F]})), " - + "CrossJoin({[Product].[Food]}, {[Gender].[M]}))), Union(Union(CrossJoin({[Product].[Non-Consumable]}, " - + "{[Gender].[All Gender]}), CrossJoin({[Product].[Non-Consumable]}, {[Gender].[F]})), " - + "CrossJoin({[Product].[Non-Consumable]}, {[Gender].[M]}))) ON ROWS FROM [Sales]"); + AbstractTransformTestCase { + + private String initialQuery = "select {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS," + + " Hierarchize(Union(Union(Union(Crossjoin({[Promotion Media].[All Media]}, {[Product].[All Products]}), " + + "Crossjoin({[Promotion Media].[All Media]}, [Product].[All Products].Children)), Crossjoin({[Promotion Media].[All Media]}, " + + "[Product].[Drink].Children)), Crossjoin({[Promotion Media].[All Media]}, [Product].[Drink].[Beverages].Children))) ON ROWS " + + "from [Sales] where [Time].[1997]"; + + /** + * @return the initialQuery + * @see + * org.pivot4j.transform.impl.AbstractTransformTestCase#getInitialQuery() + */ + protected String getInitialQuery() { + return initialQuery; + } + + /** + * @see org.pivot4j.transform.impl.AbstractTransformTestCase#getType() + */ + @Override + protected Class getType() { + return PlaceLevelsOnAxes.class; + } + + @Test + public void testFindVisibleLevels() throws OlapException { + PlaceLevelsOnAxes transform = getTransform(); + + Cube cube = getPivotModel().getCube(); + + Hierarchy promotionMedia = cube.getHierarchies().get("Promotion Media"); + Hierarchy product = cube.getHierarchies().get("Product"); + + List firstLevels = transform.findVisibleLevels(promotionMedia); + assertThat( + "The number of visible levels in [Promotion Media] hierarchy should be 1", + firstLevels.size(), is(equalTo(1))); + assertThat( + "The first level of the hierarchy should be [Promotion Media].[(All)]", + promotionMedia.getLevels().get(0).getUniqueName(), + is(equalTo(firstLevels.get(0).getUniqueName()))); + + List allLevels = transform.findVisibleLevels(Axis.ROWS); + + assertThat("Visible levels should not be empty", allLevels.isEmpty(), + is(false)); + assertThat("The number of visible levels should be 5", + allLevels.size(), is(equalTo(5))); + assertThat( + "The first level of the axis should be [Promotion Media].[(All)]", + promotionMedia.getLevels().get(0).getUniqueName(), + is(equalTo(allLevels.get(0).getUniqueName()))); + + assertThat("The second level of the axis should be [Product].[(All)]", + product.getLevels().get(0).getUniqueName(), + is(equalTo(allLevels.get(1).getUniqueName()))); + assertThat( + "The third level of the axis should be [Product].[Product Family]", + product.getLevels().get(1).getUniqueName(), + is(equalTo(allLevels.get(2).getUniqueName()))); + assertThat( + "The fourth level of the axis should be [Product].[Product Department]", + product.getLevels().get(2).getUniqueName(), + is(equalTo(allLevels.get(3).getUniqueName()))); + assertThat( + "The fourth level of the axis should be [Product].[Product Category]", + product.getLevels().get(3).getUniqueName(), + is(equalTo(allLevels.get(4).getUniqueName()))); + } + + @Test + public void testAddLevelOnExisiingHierarchy() throws OlapException { + PlaceLevelsOnAxes transform = getTransform(); + + Cube cube = getPivotModel().getCube(); + + Hierarchy promotionMedia = cube.getHierarchies().get("Promotion Media"); + Level level = promotionMedia.getLevels().get(1); + + transform.addLevel(Axis.ROWS, level, -1); + + assertThat( + "Unexpected MDX query", + getPivotModel().getCurrentMdx(), + is(equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "CrossJoin({[Promotion Media].[All Media], [Promotion Media].[Bulk Mail], [Promotion Media].[Cash Register Handout], " + + "[Promotion Media].[Daily Paper], [Promotion Media].[Daily Paper, Radio], " + + "[Promotion Media].[Daily Paper, Radio, TV], [Promotion Media].[In-Store Coupon], [Promotion Media].[No Media], " + + "[Promotion Media].[Product Attachment], [Promotion Media].[Radio], [Promotion Media].[Street Handout], " + + "[Promotion Media].[Sunday Paper], [Promotion Media].[Sunday Paper, Radio], " + + "[Promotion Media].[Sunday Paper, Radio, TV], [Promotion Media].[TV]}, {[Product].[All Products], " + + "[Product].[Drink], [Product].[Drink].[Alcoholic Beverages], [Product].[Drink].[Beverages], " + + "[Product].[Drink].[Beverages].[Carbonated Beverages], [Product].[Drink].[Beverages].[Drinks], " + + "[Product].[Drink].[Beverages].[Hot Beverages], [Product].[Drink].[Beverages].[Pure Juice Beverages], " + + "[Product].[Drink].[Dairy], [Product].[Food], [Product].[Non-Consumable]}) ON ROWS " + + "FROM [Sales] WHERE [Time].[1997]"))); + } + + @Test + public void testAddLevelAtTheBeginning() throws OlapException { + PlaceLevelsOnAxes transform = getTransform(); + + Cube cube = getPivotModel().getCube(); + + Hierarchy gender = cube.getHierarchies().get("Gender"); + Level level = gender.getLevels().get(1); + + transform.addLevel(Axis.ROWS, level, 0); + + assertThat( + "Unexpected MDX query", + getPivotModel().getCurrentMdx(), + is(equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "CrossJoin({[Gender].[F], [Gender].[M]}, CrossJoin({[Promotion Media].[All Media]}, {[Product].[All Products], " + + "[Product].[Drink], [Product].[Drink].[Alcoholic Beverages], [Product].[Drink].[Beverages], " + + "[Product].[Drink].[Beverages].[Carbonated Beverages], [Product].[Drink].[Beverages].[Drinks], " + + "[Product].[Drink].[Beverages].[Hot Beverages], [Product].[Drink].[Beverages].[Pure Juice Beverages], " + + "[Product].[Drink].[Dairy], [Product].[Food], [Product].[Non-Consumable]})) ON ROWS " + + "FROM [Sales] WHERE [Time].[1997]"))); + } + + @Test + public void testPlaceLevels() throws OlapException { + PlaceLevelsOnAxes transform = getTransform(); + + Cube cube = getPivotModel().getCube(); + + Hierarchy gender = cube.getHierarchies().get("Gender"); + Hierarchy store = cube.getHierarchies().get("Store"); + + List levels = new ArrayList(); + levels.add(gender.getLevels().get(0)); + levels.add(store.getLevels().get(1)); + + transform.placeLevels(Axis.ROWS, levels); + + assertThat( + "Unexpected MDX query", + getPivotModel().getCurrentMdx(), + is(equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "CrossJoin({[Gender].[All Gender]}, {[Store].[Canada], [Store].[Mexico], [Store].[USA]}) ON ROWS " + + "FROM [Sales] WHERE [Time].[1997]"))); + } + + @Test + public void testAddLevelAtTheMiddle() throws OlapException { + PlaceLevelsOnAxes transform = getTransform(); + + Cube cube = getPivotModel().getCube(); + + Hierarchy gender = cube.getHierarchies().get("Gender"); + Level level = gender.getLevels().get(1); + + transform.addLevel(Axis.ROWS, level, 1); + + assertThat( + "Unexpected MDX query", + getPivotModel().getCurrentMdx(), + is(equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "CrossJoin({[Promotion Media].[All Media]}, CrossJoin({[Gender].[F], [Gender].[M]}, " + + "{[Product].[All Products], [Product].[Drink], [Product].[Drink].[Alcoholic Beverages], " + + "[Product].[Drink].[Beverages], [Product].[Drink].[Beverages].[Carbonated Beverages], " + + "[Product].[Drink].[Beverages].[Drinks], [Product].[Drink].[Beverages].[Hot Beverages], " + + "[Product].[Drink].[Beverages].[Pure Juice Beverages], [Product].[Drink].[Dairy], " + + "[Product].[Food], [Product].[Non-Consumable]})) ON ROWS FROM [Sales] WHERE [Time].[1997]"))); + } + + @Test + public void testAddLevelAtTheEnd() throws OlapException { + PlaceLevelsOnAxes transform = getTransform(); + + Cube cube = getPivotModel().getCube(); + + Hierarchy gender = cube.getHierarchies().get("Gender"); + Level level = gender.getLevels().get(1); + + transform.addLevel(Axis.ROWS, level, 2); + + assertThat( + "Unexpected MDX query", + getPivotModel().getCurrentMdx(), + is(equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "CrossJoin({[Promotion Media].[All Media]}, CrossJoin({[Product].[All Products], [Product].[Drink], " + + "[Product].[Drink].[Alcoholic Beverages], [Product].[Drink].[Beverages], [Product].[Drink].[Beverages].[Carbonated Beverages], " + + "[Product].[Drink].[Beverages].[Drinks], [Product].[Drink].[Beverages].[Hot Beverages], " + + "[Product].[Drink].[Beverages].[Pure Juice Beverages], [Product].[Drink].[Dairy], [Product].[Food], " + + "[Product].[Non-Consumable]}, {[Gender].[F], [Gender].[M]})) ON ROWS FROM [Sales] WHERE [Time].[1997]"))); + } + + @Test + public void testRemoveLevel() throws OlapException { + PlaceLevelsOnAxes transform = getTransform(); + + Cube cube = getPivotModel().getCube(); + + Hierarchy product = cube.getHierarchies().get("Product"); + + Level level = product.getLevels().get("Product Department"); + + transform.removeLevel(Axis.ROWS, level); + + assertThat( + "Unexpected MDX query", + getPivotModel().getCurrentMdx(), + is(equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "CrossJoin({[Promotion Media].[All Media]}, {[Product].[All Products], [Product].[Drink], " + + "[Product].[Drink].[Beverages].[Carbonated Beverages], [Product].[Drink].[Beverages].[Drinks], " + + "[Product].[Drink].[Beverages].[Hot Beverages], [Product].[Drink].[Beverages].[Pure Juice Beverages], " + + "[Product].[Food], [Product].[Non-Consumable]}) ON ROWS FROM [Sales] WHERE [Time].[1997]"))); + } + + @Test + public void testRemoveLevelFromCrossJoinedAxis() throws OlapException { + PlaceLevelsOnAxes transform = getTransform(); + + PivotModel model = getPivotModel(); + model.setMdx("SELECT {[Measures].[Unit Sales]} ON COLUMNS, Union(Union({([Product].[All Products], [Gender].[All Gender])}, " + + "Union(Union(CrossJoin({[Product].[Food]}, {[Gender].[All Gender]}), CrossJoin({[Product].[Food]}, {[Gender].[F]})), " + + "CrossJoin({[Product].[Food]}, {[Gender].[M]}))), Union(Union(CrossJoin({[Product].[Non-Consumable]}, " + + "{[Gender].[All Gender]}), CrossJoin({[Product].[Non-Consumable]}, {[Gender].[F]})), " + + "CrossJoin({[Product].[Non-Consumable]}, {[Gender].[M]}))) ON ROWS FROM [Sales]"); - Cube cube = getPivotModel().getCube(); + Cube cube = getPivotModel().getCube(); - Hierarchy product = cube.getHierarchies().get("Product"); + Hierarchy product = cube.getHierarchies().get("Product"); - Level level = product.getLevels().get("(All)"); - - transform.removeLevel(Axis.ROWS, level); + Level level = product.getLevels().get("(All)"); + + transform.removeLevel(Axis.ROWS, level); - assertThat( - "Unexpected MDX query", - getPivotModel().getCurrentMdx(), - is(equalTo("SELECT {[Measures].[Unit Sales]} ON COLUMNS, CrossJoin({[Product].[Food], [Product].[Non-Consumable]}, " - + "{[Gender].[All Gender], [Gender].[F], [Gender].[M]}) ON ROWS FROM [Sales]"))); - } + assertThat( + "Unexpected MDX query", + getPivotModel().getCurrentMdx(), + is(equalTo("SELECT {[Measures].[Unit Sales]} ON COLUMNS, CrossJoin({[Product].[Food], [Product].[Non-Consumable]}, " + + "{[Gender].[All Gender], [Gender].[F], [Gender].[M]}) ON ROWS FROM [Sales]"))); + } } diff --git a/pivot4j-core/src/test/java/org/pivot4j/transform/impl/PlaceMembersOnAxesImplIT.java b/pivot4j-core/src/test/java/org/pivot4j/transform/impl/PlaceMembersOnAxesImplIT.java index ad1ba8f8..3e2ccdfc 100644 --- a/pivot4j-core/src/test/java/org/pivot4j/transform/impl/PlaceMembersOnAxesImplIT.java +++ b/pivot4j-core/src/test/java/org/pivot4j/transform/impl/PlaceMembersOnAxesImplIT.java @@ -26,223 +26,224 @@ import org.pivot4j.transform.PlaceMembersOnAxes; public class PlaceMembersOnAxesImplIT extends - AbstractTransformTestCase { + AbstractTransformTestCase { - private String initialQuery = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales]"; + private String initialQuery = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales]"; - /** - * @return the initialQuery - * @see org.pivot4j.transform.impl.AbstractTransformTestCase#getInitialQuery() - */ - protected String getInitialQuery() { - return initialQuery; - } + /** + * @return the initialQuery + * @see + * org.pivot4j.transform.impl.AbstractTransformTestCase#getInitialQuery() + */ + protected String getInitialQuery() { + return initialQuery; + } - /** - * @see org.pivot4j.transform.impl.AbstractTransformTestCase#getType() - */ - @Override - protected Class getType() { - return PlaceMembersOnAxes.class; - } + /** + * @see org.pivot4j.transform.impl.AbstractTransformTestCase#getType() + */ + @Override + protected Class getType() { + return PlaceMembersOnAxes.class; + } - @Test - public void testFindVisibleMembers() throws OlapException { - PlaceMembersOnAxes transform = getTransform(); + @Test + public void testFindVisibleMembers() throws OlapException { + PlaceMembersOnAxes transform = getTransform(); - Cube cube = getPivotModel().getCube(); + Cube cube = getPivotModel().getCube(); - Hierarchy promotionMedia = cube.getHierarchies().get("Promotion Media"); + Hierarchy promotionMedia = cube.getHierarchies().get("Promotion Media"); - List mediaMembers = transform - .findVisibleMembers(promotionMedia); + List mediaMembers = transform + .findVisibleMembers(promotionMedia); - assertThat("[Promotion Media].[All Media] member should be visible", - mediaMembers, is(notNullValue())); - assertThat("[Promotion Media].[All Media] member should be visible", - mediaMembers.isEmpty(), is(false)); - assertThat("Only [Promotion Media].[All Media] member is visible", - mediaMembers.size(), is(equalTo(1))); - } + assertThat("[Promotion Media].[All Media] member should be visible", + mediaMembers, is(notNullValue())); + assertThat("[Promotion Media].[All Media] member should be visible", + mediaMembers.isEmpty(), is(false)); + assertThat("Only [Promotion Media].[All Media] member is visible", + mediaMembers.size(), is(equalTo(1))); + } - @Test - public void testPlaceMembers() throws OlapException { - PlaceMembersOnAxes transform = getTransform(); + @Test + public void testPlaceMembers() throws OlapException { + PlaceMembersOnAxes transform = getTransform(); - Cube cube = getPivotModel().getCube(); + Cube cube = getPivotModel().getCube(); - Hierarchy promotionMedia = cube.getHierarchies().get("Promotion Media"); - Hierarchy product = cube.getHierarchies().get("Product"); + Hierarchy promotionMedia = cube.getHierarchies().get("Promotion Media"); + Hierarchy product = cube.getHierarchies().get("Product"); - List members = new ArrayList(); + List members = new ArrayList(); - Member allMedia = promotionMedia.getDefaultMember(); - Member allProducts = product.getDefaultMember(); + Member allMedia = promotionMedia.getDefaultMember(); + Member allProducts = product.getDefaultMember(); - members.add(allMedia); - members.add(allMedia.getChildMembers().get("Bulk Mail")); - members.add(allMedia.getChildMembers().get("Daily Paper")); + members.add(allMedia); + members.add(allMedia.getChildMembers().get("Bulk Mail")); + members.add(allMedia.getChildMembers().get("Daily Paper")); - members.add(allProducts.getChildMembers().get("Food")); - members.add(allProducts.getChildMembers().get("Drink")); + members.add(allProducts.getChildMembers().get("Food")); + members.add(allProducts.getChildMembers().get("Drink")); - transform.placeMembers(Axis.ROWS, members); + transform.placeMembers(Axis.ROWS, members); - assertThat( - "Unexpected MDX query", - getPivotModel().getCurrentMdx(), - is(equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "CrossJoin({[Promotion Media].[All Media], [Promotion Media].[Bulk Mail], [Promotion Media].[Daily Paper]}, " - + "{[Product].[Food], [Product].[Drink]}) ON ROWS FROM [Sales]"))); + assertThat( + "Unexpected MDX query", + getPivotModel().getCurrentMdx(), + is(equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "CrossJoin({[Promotion Media].[All Media], [Promotion Media].[Bulk Mail], [Promotion Media].[Daily Paper]}, " + + "{[Product].[Food], [Product].[Drink]}) ON ROWS FROM [Sales]"))); - getPivotModel().getCellSet(); - } + getPivotModel().getCellSet(); + } - @Test - public void testAddMemberAtIndexMinusOne() throws OlapException { - PlaceMembersOnAxes transform = getTransform(); + @Test + public void testAddMemberAtIndexMinusOne() throws OlapException { + PlaceMembersOnAxes transform = getTransform(); - Cube cube = getPivotModel().getCube(); + Cube cube = getPivotModel().getCube(); - Member member = cube.lookupMember(IdentifierNode.parseIdentifier( - "[Measures].[Profit]").getSegmentList()); + Member member = cube.lookupMember(IdentifierNode.parseIdentifier( + "[Measures].[Profit]").getSegmentList()); - transform.addMember(member, -1); + transform.addMember(member, -1); - assertThat( - "Unexpected MDX query", - getPivotModel().getCurrentMdx(), - is(equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales], [Measures].[Profit]} ON COLUMNS, " - + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales]"))); + assertThat( + "Unexpected MDX query", + getPivotModel().getCurrentMdx(), + is(equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales], [Measures].[Profit]} ON COLUMNS, " + + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales]"))); - getPivotModel().getCellSet(); - } + getPivotModel().getCellSet(); + } - @Test - public void testAddMemberAtIndexZero() throws OlapException { - PlaceMembersOnAxes transform = getTransform(); + @Test + public void testAddMemberAtIndexZero() throws OlapException { + PlaceMembersOnAxes transform = getTransform(); - Cube cube = getPivotModel().getCube(); + Cube cube = getPivotModel().getCube(); - Member member = cube.lookupMember(IdentifierNode.parseIdentifier( - "[Measures].[Profit]").getSegmentList()); + Member member = cube.lookupMember(IdentifierNode.parseIdentifier( + "[Measures].[Profit]").getSegmentList()); - transform.addMember(member, 0); + transform.addMember(member, 0); - assertThat( - "Unexpected MDX query", - getPivotModel().getCurrentMdx(), - is(equalTo("SELECT {[Measures].[Profit], [Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales]"))); + assertThat( + "Unexpected MDX query", + getPivotModel().getCurrentMdx(), + is(equalTo("SELECT {[Measures].[Profit], [Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales]"))); - getPivotModel().getCellSet(); - } + getPivotModel().getCellSet(); + } - @Test - public void testAddMemberAtIndexOne() throws OlapException { - PlaceMembersOnAxes transform = getTransform(); + @Test + public void testAddMemberAtIndexOne() throws OlapException { + PlaceMembersOnAxes transform = getTransform(); - Cube cube = getPivotModel().getCube(); + Cube cube = getPivotModel().getCube(); - Member member = cube.lookupMember(IdentifierNode.parseIdentifier( - "[Measures].[Profit]").getSegmentList()); + Member member = cube.lookupMember(IdentifierNode.parseIdentifier( + "[Measures].[Profit]").getSegmentList()); - transform.addMember(member, 1); + transform.addMember(member, 1); - assertThat( - "Unexpected MDX query", - getPivotModel().getCurrentMdx(), - is(equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Profit], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales]"))); + assertThat( + "Unexpected MDX query", + getPivotModel().getCurrentMdx(), + is(equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Profit], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales]"))); - getPivotModel().getCellSet(); - } + getPivotModel().getCellSet(); + } - @Test - public void testAddMembers() throws OlapException { - PlaceMembersOnAxes transform = getTransform(); + @Test + public void testAddMembers() throws OlapException { + PlaceMembersOnAxes transform = getTransform(); - Cube cube = getPivotModel().getCube(); + Cube cube = getPivotModel().getCube(); - List members = new ArrayList(2); - members.add(cube.lookupMember(IdentifierNode.parseIdentifier( - "[Measures].[Profit]").getSegmentList())); - members.add(cube.lookupMember(IdentifierNode.parseIdentifier( - "[Measures].[Sales Count]").getSegmentList())); + List members = new ArrayList(2); + members.add(cube.lookupMember(IdentifierNode.parseIdentifier( + "[Measures].[Profit]").getSegmentList())); + members.add(cube.lookupMember(IdentifierNode.parseIdentifier( + "[Measures].[Sales Count]").getSegmentList())); - transform.addMembers(cube.getHierarchies().get("Measures"), members); + transform.addMembers(cube.getHierarchies().get("Measures"), members); - assertThat( - "Unexpected MDX query", - getPivotModel().getCurrentMdx(), - is(equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales], " - + "[Measures].[Profit], [Measures].[Sales Count]} ON COLUMNS, " - + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales]"))); + assertThat( + "Unexpected MDX query", + getPivotModel().getCurrentMdx(), + is(equalTo("SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales], " + + "[Measures].[Profit], [Measures].[Sales Count]} ON COLUMNS, " + + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales]"))); - getPivotModel().getCellSet(); - } + getPivotModel().getCellSet(); + } - @Test - public void testMoveMember() throws OlapException { - PlaceMembersOnAxes transform = getTransform(); + @Test + public void testMoveMember() throws OlapException { + PlaceMembersOnAxes transform = getTransform(); - Cube cube = getPivotModel().getCube(); + Cube cube = getPivotModel().getCube(); - Member member = cube.lookupMember(IdentifierNode.parseIdentifier( - "[Measures].[Unit Sales]").getSegmentList()); + Member member = cube.lookupMember(IdentifierNode.parseIdentifier( + "[Measures].[Unit Sales]").getSegmentList()); - transform.moveMember(member, 2); + transform.moveMember(member, 2); - assertThat( - "Unexpected MDX query", - getPivotModel().getCurrentMdx(), - is(equalTo("SELECT {[Measures].[Store Cost], [Measures].[Unit Sales], [Measures].[Store Sales]} ON COLUMNS, " - + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales]"))); + assertThat( + "Unexpected MDX query", + getPivotModel().getCurrentMdx(), + is(equalTo("SELECT {[Measures].[Store Cost], [Measures].[Unit Sales], [Measures].[Store Sales]} ON COLUMNS, " + + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales]"))); - getPivotModel().getCellSet(); - } + getPivotModel().getCellSet(); + } - @Test - public void testRemoveMember() throws OlapException { - PlaceMembersOnAxes transform = getTransform(); + @Test + public void testRemoveMember() throws OlapException { + PlaceMembersOnAxes transform = getTransform(); - Cube cube = getPivotModel().getCube(); + Cube cube = getPivotModel().getCube(); - Member member = cube.lookupMember(IdentifierNode.parseIdentifier( - "[Measures].[Unit Sales]").getSegmentList()); + Member member = cube.lookupMember(IdentifierNode.parseIdentifier( + "[Measures].[Unit Sales]").getSegmentList()); - transform.removeMember(member); + transform.removeMember(member); - assertThat( - "Unexpected MDX query", - getPivotModel().getCurrentMdx(), - is(equalTo("SELECT {[Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales]"))); + assertThat( + "Unexpected MDX query", + getPivotModel().getCurrentMdx(), + is(equalTo("SELECT {[Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales]"))); - getPivotModel().getCellSet(); - } + getPivotModel().getCellSet(); + } - @Test - public void testRemoveMembers() throws OlapException { - PlaceMembersOnAxes transform = getTransform(); + @Test + public void testRemoveMembers() throws OlapException { + PlaceMembersOnAxes transform = getTransform(); - Cube cube = getPivotModel().getCube(); + Cube cube = getPivotModel().getCube(); - List members = new ArrayList(2); - members.add(cube.lookupMember(IdentifierNode.parseIdentifier( - "[Measures].[Unit Sales]").getSegmentList())); - members.add(cube.lookupMember(IdentifierNode.parseIdentifier( - "[Measures].[Store Sales]").getSegmentList())); + List members = new ArrayList(2); + members.add(cube.lookupMember(IdentifierNode.parseIdentifier( + "[Measures].[Unit Sales]").getSegmentList())); + members.add(cube.lookupMember(IdentifierNode.parseIdentifier( + "[Measures].[Store Sales]").getSegmentList())); - transform.removeMembers(cube.getHierarchies().get("Measures"), members); + transform.removeMembers(cube.getHierarchies().get("Measures"), members); - assertThat( - "Unexpected MDX query", - getPivotModel().getCurrentMdx(), - is(equalTo("SELECT {[Measures].[Store Cost]} ON COLUMNS, " - + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales]"))); + assertThat( + "Unexpected MDX query", + getPivotModel().getCurrentMdx(), + is(equalTo("SELECT {[Measures].[Store Cost]} ON COLUMNS, " + + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales]"))); - getPivotModel().getCellSet(); - } + getPivotModel().getCellSet(); + } } diff --git a/pivot4j-core/src/test/java/org/pivot4j/transform/impl/SwapAxesImplIT.java b/pivot4j-core/src/test/java/org/pivot4j/transform/impl/SwapAxesImplIT.java index d4f0927a..19a22952 100644 --- a/pivot4j-core/src/test/java/org/pivot4j/transform/impl/SwapAxesImplIT.java +++ b/pivot4j-core/src/test/java/org/pivot4j/transform/impl/SwapAxesImplIT.java @@ -17,59 +17,60 @@ public class SwapAxesImplIT extends AbstractTransformTestCase { - private String initialQuery = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales]"; - - /** - * @return the initialQuery - * @see org.pivot4j.transform.impl.AbstractTransformTestCase#getInitialQuery() - */ - protected String getInitialQuery() { - return initialQuery; - } - - /** - * @see org.pivot4j.transform.impl.AbstractTransformTestCase#getType() - */ - @Override - protected Class getType() { - return SwapAxes.class; - } - - @Test - public void testTransform() { - SwapAxes transform = getTransform(); - - assertThat("Initial query axes are not swapped", - transform.isSwapAxes(), is(false)); - assertThat("Should be able to swap axes on initial query", - transform.canSwapAxes(), is(true)); - - transform.setSwapAxes(true); - - assertThat("Query axes have been swapped", transform.isSwapAxes(), - is(true)); - - assertThat( - "Unexpected MDX query after axes have been swapped", - getPivotModel().getCurrentMdx(), - is(equalTo("SELECT {([Promotion Media].[All Media], [Product].[All Products])} ON COLUMNS, " - + "{[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON ROWS " - + "FROM [Sales]"))); - - getPivotModel().getCellSet(); - - transform.setSwapAxes(false); - - assertThat("Unexpected MDX query after axes have been restored", - getPivotModel().getCurrentMdx(), is(equalTo(getInitialQuery()))); - - getPivotModel().getCellSet(); - - getPivotModel() - .setMdx("SELECT {([Promotion Media].[All Media], [Product].[All Products])} ON COLUMNS FROM [Sales]"); - - assertThat("Single query axis cannot be swapped with itself", - transform.canSwapAxes(), is(false)); - } + private String initialQuery = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "{([Promotion Media].[All Media], [Product].[All Products])} ON ROWS FROM [Sales]"; + + /** + * @return the initialQuery + * @see + * org.pivot4j.transform.impl.AbstractTransformTestCase#getInitialQuery() + */ + protected String getInitialQuery() { + return initialQuery; + } + + /** + * @see org.pivot4j.transform.impl.AbstractTransformTestCase#getType() + */ + @Override + protected Class getType() { + return SwapAxes.class; + } + + @Test + public void testTransform() { + SwapAxes transform = getTransform(); + + assertThat("Initial query axes are not swapped", + transform.isSwapAxes(), is(false)); + assertThat("Should be able to swap axes on initial query", + transform.canSwapAxes(), is(true)); + + transform.setSwapAxes(true); + + assertThat("Query axes have been swapped", transform.isSwapAxes(), + is(true)); + + assertThat( + "Unexpected MDX query after axes have been swapped", + getPivotModel().getCurrentMdx(), + is(equalTo("SELECT {([Promotion Media].[All Media], [Product].[All Products])} ON COLUMNS, " + + "{[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON ROWS " + + "FROM [Sales]"))); + + getPivotModel().getCellSet(); + + transform.setSwapAxes(false); + + assertThat("Unexpected MDX query after axes have been restored", + getPivotModel().getCurrentMdx(), is(equalTo(getInitialQuery()))); + + getPivotModel().getCellSet(); + + getPivotModel() + .setMdx("SELECT {([Promotion Media].[All Media], [Product].[All Products])} ON COLUMNS FROM [Sales]"); + + assertThat("Single query axis cannot be swapped with itself", + transform.canSwapAxes(), is(false)); + } } diff --git a/pivot4j-core/src/test/java/org/pivot4j/ui/AbstractHtmlTableTestCase.java b/pivot4j-core/src/test/java/org/pivot4j/ui/AbstractHtmlTableTestCase.java index 40ff7fbf..001d8f52 100644 --- a/pivot4j-core/src/test/java/org/pivot4j/ui/AbstractHtmlTableTestCase.java +++ b/pivot4j-core/src/test/java/org/pivot4j/ui/AbstractHtmlTableTestCase.java @@ -35,164 +35,163 @@ import com.gargoylesoftware.htmlunit.html.HtmlTableRow; public abstract class AbstractHtmlTableTestCase extends - AbstractIntegrationTestCase { - - private boolean deleteTestFile = true; - - private HtmlTable table; - - /** - * @return the table - */ - protected HtmlTable getTable() { - return table; - } - - /** - * @return the deleteTestFile - */ - protected boolean getDeleteTestFile() { - return deleteTestFile; - } - - /** - * @param deleteTestFile - * the deleteTestFile to set - */ - protected void setDeleteTestFile(boolean deleteTestFile) { - this.deleteTestFile = deleteTestFile; - } - - protected abstract String getQueryName(); - - /** - * @see org.pivot4j.AbstractIntegrationTestCase#setUp() - */ - @Override - public void setUp() throws Exception { - super.setUp(); - - PivotModel model = getPivotModel(); - model.setMdx(readTestResource(getQueryName() + ".txt")); - model.initialize(); - - Writer writer = null; - - File file = File.createTempFile("pivot4j-", ".html"); - - if (deleteTestFile) { - file.deleteOnExit(); - } - - try { - TableRenderer renderer = new TableRenderer(); - configureRenderer(renderer); - - writer = new FileWriter(file); - - HtmlRenderCallback callback = new HtmlRenderCallback(writer); - callback.setTableId("pivot"); - callback.setBorder(1); - - renderer.render(model, callback); - } finally { - writer.flush(); - IOUtils.closeQuietly(writer); - } - - WebClient webClient = new WebClient(); - HtmlPage page = webClient.getPage(file.toURI().toURL()); - - this.table = page.getHtmlElementById("pivot"); - - assertThat("Table element is not found.", table, is(notNullValue())); - } - - /** - * @see org.pivot4j.AbstractIntegrationTestCase#tearDown() - */ - @Override - public void tearDown() throws Exception { - super.tearDown(); - - this.table = null; - } - - /** - * @param renderer - */ - protected void configureRenderer(TableRenderer renderer) { - renderer.setHideSpans(false); - renderer.setShowDimensionTitle(true); - renderer.setShowParentMembers(true); - } - - /** - * @param rows - * @param rowIndex - * @param colIndex - * @param rowSpan - * @param colSpan - * @param label - */ - protected void assertCell(List rows, int rowIndex, - int colIndex, int rowSpan, int colSpan, String label) { - String coords = String.format("(%s, %s).", rowIndex, colIndex); - - assertThat("Insufficient row count" + coords, rows.size(), - is(greaterThan(rowIndex))); - - HtmlTableRow row = rows.get(rowIndex); - - assertThat("Insufficient column count" + coords, row.getCells().size(), - is(greaterThan(colIndex))); - - HtmlTableCell cell = row.getCell(colIndex); - - assertThat("Wrong row span of header cell" + coords, cell.getRowSpan(), - is(equalTo(rowSpan))); - - assertThat("Wrong column span of header cell" + coords, - cell.getColumnSpan(), is(equalTo(colSpan))); - - if (label != null) { - assertThat("Unexpected cell content" + coords, - cell.getTextContent(), is(equalToIgnoringWhiteSpace(label))); - } - } - - /** - * @param rows - * @param rowIndex - * @param colIndex - * @return - */ - protected Map getCellStyles(List rows, - int rowIndex, int colIndex) { - Map styles = new HashMap(); - - HtmlTableRow row = rows.get(rowIndex); - - if (row != null) { - HtmlTableCell cell = row.getCell(colIndex); - - if (cell != null) { - String style = cell.getAttribute("style"); - - if (style != null) { - String[] pairs = style.split(";"); - - for (String pair : pairs) { - String[] values = pair.split(":"); - - if (values.length == 2) { - styles.put(values[0].trim(), values[1].trim()); - } - } - } - } - } - - return styles; - } + AbstractIntegrationTestCase { + + private boolean deleteTestFile = true; + + private HtmlTable table; + + /** + * @return the table + */ + protected HtmlTable getTable() { + return table; + } + + /** + * @return the deleteTestFile + */ + protected boolean getDeleteTestFile() { + return deleteTestFile; + } + + /** + * @param deleteTestFile the deleteTestFile to set + */ + protected void setDeleteTestFile(boolean deleteTestFile) { + this.deleteTestFile = deleteTestFile; + } + + protected abstract String getQueryName(); + + /** + * @see org.pivot4j.AbstractIntegrationTestCase#setUp() + */ + @Override + public void setUp() throws Exception { + super.setUp(); + + PivotModel model = getPivotModel(); + model.setMdx(readTestResource(getQueryName() + ".txt")); + model.initialize(); + + Writer writer = null; + + File file = File.createTempFile("pivot4j-", ".html"); + + if (deleteTestFile) { + file.deleteOnExit(); + } + + try { + TableRenderer renderer = new TableRenderer(); + configureRenderer(renderer); + + writer = new FileWriter(file); + + HtmlRenderCallback callback = new HtmlRenderCallback(writer); + callback.setTableId("pivot"); + callback.setBorder(1); + + renderer.render(model, callback); + } finally { + writer.flush(); + IOUtils.closeQuietly(writer); + } + + WebClient webClient = new WebClient(); + HtmlPage page = webClient.getPage(file.toURI().toURL()); + + this.table = page.getHtmlElementById("pivot"); + + assertThat("Table element is not found.", table, is(notNullValue())); + } + + /** + * @see org.pivot4j.AbstractIntegrationTestCase#tearDown() + */ + @Override + public void tearDown() throws Exception { + super.tearDown(); + + this.table = null; + } + + /** + * @param renderer + */ + protected void configureRenderer(TableRenderer renderer) { + renderer.setHideSpans(false); + renderer.setShowDimensionTitle(true); + renderer.setShowParentMembers(true); + } + + /** + * @param rows + * @param rowIndex + * @param colIndex + * @param rowSpan + * @param colSpan + * @param label + */ + protected void assertCell(List rows, int rowIndex, + int colIndex, int rowSpan, int colSpan, String label) { + String coords = String.format("(%s, %s).", rowIndex, colIndex); + + assertThat("Insufficient row count" + coords, rows.size(), + is(greaterThan(rowIndex))); + + HtmlTableRow row = rows.get(rowIndex); + + assertThat("Insufficient column count" + coords, row.getCells().size(), + is(greaterThan(colIndex))); + + HtmlTableCell cell = row.getCell(colIndex); + + assertThat("Wrong row span of header cell" + coords, cell.getRowSpan(), + is(equalTo(rowSpan))); + + assertThat("Wrong column span of header cell" + coords, + cell.getColumnSpan(), is(equalTo(colSpan))); + + if (label != null) { + assertThat("Unexpected cell content" + coords, + cell.getTextContent(), is(equalToIgnoringWhiteSpace(label))); + } + } + + /** + * @param rows + * @param rowIndex + * @param colIndex + * @return + */ + protected Map getCellStyles(List rows, + int rowIndex, int colIndex) { + Map styles = new HashMap(); + + HtmlTableRow row = rows.get(rowIndex); + + if (row != null) { + HtmlTableCell cell = row.getCell(colIndex); + + if (cell != null) { + String style = cell.getAttribute("style"); + + if (style != null) { + String[] pairs = style.split(";"); + + for (String pair : pairs) { + String[] values = pair.split(":"); + + if (values.length == 2) { + styles.put(values[0].trim(), values[1].trim()); + } + } + } + } + } + + return styles; + } } diff --git a/pivot4j-core/src/test/java/org/pivot4j/ui/AbstractMockRenderTestCase.java b/pivot4j-core/src/test/java/org/pivot4j/ui/AbstractMockRenderTestCase.java index a2dd9966..f013085c 100644 --- a/pivot4j-core/src/test/java/org/pivot4j/ui/AbstractMockRenderTestCase.java +++ b/pivot4j-core/src/test/java/org/pivot4j/ui/AbstractMockRenderTestCase.java @@ -16,8 +16,8 @@ public abstract class AbstractMockRenderTestCase { - protected TableRenderContext createDummyRenderContext() { - PivotModel model = new PivotModelImpl(new SimpleOlapDataSource()); - return new TableRenderContext(model, new TableRenderer(), 5, 10, 2, 2); - } + protected TableRenderContext createDummyRenderContext() { + PivotModel model = new PivotModelImpl(new SimpleOlapDataSource()); + return new TableRenderContext(model, new TableRenderer(), 5, 10, 2, 2); + } } diff --git a/pivot4j-core/src/test/java/org/pivot4j/ui/aggregator/AggregationWithParentHiddenIT.java b/pivot4j-core/src/test/java/org/pivot4j/ui/aggregator/AggregationWithParentHiddenIT.java index 78643a01..4d549903 100644 --- a/pivot4j-core/src/test/java/org/pivot4j/ui/aggregator/AggregationWithParentHiddenIT.java +++ b/pivot4j-core/src/test/java/org/pivot4j/ui/aggregator/AggregationWithParentHiddenIT.java @@ -32,143 +32,144 @@ public class AggregationWithParentHiddenIT extends AbstractHtmlTableTestCase { - /** - * @see org.pivot4j.ui.AbstractHtmlTableTestCase#getQueryName() - */ - @Override - protected String getQueryName() { - return "complex"; - } - - /** - * @see org.pivot4j.ui.AbstractHtmlTableTestCase#configureRenderer(org.pivot4j.ui.table.TableRenderer) - */ - @Override - protected void configureRenderer(TableRenderer renderer) { - super.configureRenderer(renderer); - - renderer.setShowDimensionTitle(false); - renderer.setShowParentMembers(false); - - renderer.addAggregator(Axis.ROWS, AggregatorPosition.Grand, - MinimumAggregator.NAME); - renderer.addAggregator(Axis.ROWS, AggregatorPosition.Hierarchy, - TotalAggregator.NAME); - renderer.addAggregator(Axis.ROWS, AggregatorPosition.Member, - AverageAggregator.NAME); - - renderer.addAggregator(Axis.COLUMNS, AggregatorPosition.Grand, - MinimumAggregator.NAME); - renderer.addAggregator(Axis.COLUMNS, AggregatorPosition.Hierarchy, - TotalAggregator.NAME); - renderer.addAggregator(Axis.COLUMNS, AggregatorPosition.Member, - AverageAggregator.NAME); - } - - @Test - public void testAggregation() throws IOException { - HtmlTable table = getTable(); - - HtmlTableHeader header = table.getHeader(); - - List rows = header.getRows(); - - assertThat("Table header is missing.", rows, is(notNullValue())); - assertThat("Not enough column header rows.", rows.size(), - is(equalTo(3))); - - // Column headers - assertCell(rows, 0, 0, 3, 3, null); - - assertCell(rows, 0, 1, 1, 9, "Q1"); - assertCell(rows, 0, 2, 1, 9, "Q2"); - assertCell(rows, 0, 3, 1, 9, "5"); - assertCell(rows, 0, 4, 1, 9, "6"); - assertCell(rows, 0, 5, 2, 3, "Average"); - assertCell(rows, 0, 6, 2, 3, "Total"); - assertCell(rows, 0, 7, 2, 3, "Minimum"); - - for (int i = 0; i < 4; i++) { - assertCell(rows, 1, i * 3, 1, 3, "F"); - assertCell(rows, 1, (i * 3) + 1, 1, 3, "M"); - assertCell(rows, 1, (i * 3) + 2, 1, 3, "Total"); - } - - for (int i = 0; i < 13; i++) { - assertCell(rows, 2, (i * 3), 1, 1, "Store Sales"); - assertCell(rows, 2, (i * 3) + 1, 1, 1, "Store Cost"); - assertCell(rows, 2, (i * 3) + 2, 1, 1, "Unit Sales"); - } - - // Table content - List bodies = table.getBodies(); - - assertThat("Table body is missing.", bodies, is(notNullValue())); - assertThat("Table body is missing.", bodies.size(), is(equalTo(1))); - - rows = bodies.get(0).getRows(); - - assertThat("Table content is missing.", rows, is(notNullValue())); - assertThat("Not enough content rows.", rows.size(), is(equalTo(51))); - - assertCell(rows, 0, 0, 25, 1, "Bulk Mail"); - assertCell(rows, 0, 1, 12, 1, "M"); - assertCell(rows, 0, 2, 1, 1, "Alcoholic Beverages"); - - assertCell(rows, 1, 0, 1, 1, "Beverages"); - assertCell(rows, 2, 0, 1, 1, "Dairy"); - assertCell(rows, 3, 0, 1, 1, "Average"); - assertCell(rows, 4, 0, 1, 1, "Food"); - - assertCell(rows, 5, 0, 1, 1, "Dairy"); - assertCell(rows, 6, 0, 1, 1, "Eggs"); - assertCell(rows, 7, 0, 1, 1, "Frozen Foods"); - assertCell(rows, 8, 0, 1, 1, "Average"); - assertCell(rows, 9, 0, 1, 1, "Non-Consumable"); - - // Member total title - assertCell(rows, 10, 0, 1, 1, "Average"); - assertCell(rows, 11, 0, 1, 1, "Total"); - - // Hierarchy total title - assertCell(rows, 22, 0, 1, 1, "Average"); - assertCell(rows, 23, 0, 1, 1, "Total"); - assertCell(rows, 24, 0, 1, 2, "Total"); - assertCell(rows, 49, 0, 1, 3, "Total"); - - // Axis total title - assertCell(rows, 50, 0, 1, 3, "Minimum"); - - // Row axis member aggregation - // (Bulk Mail, M, Food, Average / Q1, F, Store Sales) - assertCell(rows, 8, 7, 1, 1, "26.00"); - - // Row axis hierarchy aggregation - // (Daily Paper, S, Total / Q1, F, Store Sales) - assertCell(rows, 47, 1, 1, 1, "887.15"); - - // Row axis hierarchy aggregation - // (Daily Paper, Total / Q1, F, Store Sales) - assertCell(rows, 48, 1, 1, 1, "2,052.52"); - - // Row axis aggregation - // (Minimum / Q1, F, Store Sales) - assertCell(rows, 50, 1, 1, 1, "2.26"); - - // Column axis member aggregation - // (Bulk Mail, M, Food, Frozen Foods / Q2, 6, Average, Unit Sales) - assertCell(rows, 7, 39, 1, 1, "11"); - - // Column axis hierarchy aggregation - // (Daily Paper, S, Drink, Average / Q2, Total, Store Cost) - assertCell(rows, 40, 17, 1, 1, "7.94"); - - // Column axis hierarchy aggregation - // (Bulk Mail, M, Drink, Alcoholic Beverages / Q2, 6, Total, Store Cost) - assertCell(rows, 0, 37, 1, 1, "13.88"); - - // Column axis aggregation - // (Bulk Mail, M, Food, Frozen Foods / Minimum, Unit Sales) - assertCell(rows, 7, 45, 1, 1, "8"); - } + /** + * @see org.pivot4j.ui.AbstractHtmlTableTestCase#getQueryName() + */ + @Override + protected String getQueryName() { + return "complex"; + } + + /** + * @see + * org.pivot4j.ui.AbstractHtmlTableTestCase#configureRenderer(org.pivot4j.ui.table.TableRenderer) + */ + @Override + protected void configureRenderer(TableRenderer renderer) { + super.configureRenderer(renderer); + + renderer.setShowDimensionTitle(false); + renderer.setShowParentMembers(false); + + renderer.addAggregator(Axis.ROWS, AggregatorPosition.Grand, + MinimumAggregator.NAME); + renderer.addAggregator(Axis.ROWS, AggregatorPosition.Hierarchy, + TotalAggregator.NAME); + renderer.addAggregator(Axis.ROWS, AggregatorPosition.Member, + AverageAggregator.NAME); + + renderer.addAggregator(Axis.COLUMNS, AggregatorPosition.Grand, + MinimumAggregator.NAME); + renderer.addAggregator(Axis.COLUMNS, AggregatorPosition.Hierarchy, + TotalAggregator.NAME); + renderer.addAggregator(Axis.COLUMNS, AggregatorPosition.Member, + AverageAggregator.NAME); + } + + @Test + public void testAggregation() throws IOException { + HtmlTable table = getTable(); + + HtmlTableHeader header = table.getHeader(); + + List rows = header.getRows(); + + assertThat("Table header is missing.", rows, is(notNullValue())); + assertThat("Not enough column header rows.", rows.size(), + is(equalTo(3))); + + // Column headers + assertCell(rows, 0, 0, 3, 3, null); + + assertCell(rows, 0, 1, 1, 9, "Q1"); + assertCell(rows, 0, 2, 1, 9, "Q2"); + assertCell(rows, 0, 3, 1, 9, "5"); + assertCell(rows, 0, 4, 1, 9, "6"); + assertCell(rows, 0, 5, 2, 3, "Average"); + assertCell(rows, 0, 6, 2, 3, "Total"); + assertCell(rows, 0, 7, 2, 3, "Minimum"); + + for (int i = 0; i < 4; i++) { + assertCell(rows, 1, i * 3, 1, 3, "F"); + assertCell(rows, 1, (i * 3) + 1, 1, 3, "M"); + assertCell(rows, 1, (i * 3) + 2, 1, 3, "Total"); + } + + for (int i = 0; i < 13; i++) { + assertCell(rows, 2, (i * 3), 1, 1, "Store Sales"); + assertCell(rows, 2, (i * 3) + 1, 1, 1, "Store Cost"); + assertCell(rows, 2, (i * 3) + 2, 1, 1, "Unit Sales"); + } + + // Table content + List bodies = table.getBodies(); + + assertThat("Table body is missing.", bodies, is(notNullValue())); + assertThat("Table body is missing.", bodies.size(), is(equalTo(1))); + + rows = bodies.get(0).getRows(); + + assertThat("Table content is missing.", rows, is(notNullValue())); + assertThat("Not enough content rows.", rows.size(), is(equalTo(51))); + + assertCell(rows, 0, 0, 25, 1, "Bulk Mail"); + assertCell(rows, 0, 1, 12, 1, "M"); + assertCell(rows, 0, 2, 1, 1, "Alcoholic Beverages"); + + assertCell(rows, 1, 0, 1, 1, "Beverages"); + assertCell(rows, 2, 0, 1, 1, "Dairy"); + assertCell(rows, 3, 0, 1, 1, "Average"); + assertCell(rows, 4, 0, 1, 1, "Food"); + + assertCell(rows, 5, 0, 1, 1, "Dairy"); + assertCell(rows, 6, 0, 1, 1, "Eggs"); + assertCell(rows, 7, 0, 1, 1, "Frozen Foods"); + assertCell(rows, 8, 0, 1, 1, "Average"); + assertCell(rows, 9, 0, 1, 1, "Non-Consumable"); + + // Member total title + assertCell(rows, 10, 0, 1, 1, "Average"); + assertCell(rows, 11, 0, 1, 1, "Total"); + + // Hierarchy total title + assertCell(rows, 22, 0, 1, 1, "Average"); + assertCell(rows, 23, 0, 1, 1, "Total"); + assertCell(rows, 24, 0, 1, 2, "Total"); + assertCell(rows, 49, 0, 1, 3, "Total"); + + // Axis total title + assertCell(rows, 50, 0, 1, 3, "Minimum"); + + // Row axis member aggregation + // (Bulk Mail, M, Food, Average / Q1, F, Store Sales) + assertCell(rows, 8, 7, 1, 1, "26.00"); + + // Row axis hierarchy aggregation + // (Daily Paper, S, Total / Q1, F, Store Sales) + assertCell(rows, 47, 1, 1, 1, "887.15"); + + // Row axis hierarchy aggregation + // (Daily Paper, Total / Q1, F, Store Sales) + assertCell(rows, 48, 1, 1, 1, "2,052.52"); + + // Row axis aggregation + // (Minimum / Q1, F, Store Sales) + assertCell(rows, 50, 1, 1, 1, "2.26"); + + // Column axis member aggregation + // (Bulk Mail, M, Food, Frozen Foods / Q2, 6, Average, Unit Sales) + assertCell(rows, 7, 39, 1, 1, "11"); + + // Column axis hierarchy aggregation + // (Daily Paper, S, Drink, Average / Q2, Total, Store Cost) + assertCell(rows, 40, 17, 1, 1, "7.94"); + + // Column axis hierarchy aggregation + // (Bulk Mail, M, Drink, Alcoholic Beverages / Q2, 6, Total, Store Cost) + assertCell(rows, 0, 37, 1, 1, "13.88"); + + // Column axis aggregation + // (Bulk Mail, M, Food, Frozen Foods / Minimum, Unit Sales) + assertCell(rows, 7, 45, 1, 1, "8"); + } } diff --git a/pivot4j-core/src/test/java/org/pivot4j/ui/aggregator/CombinedAggregationWith3DimsIT.java b/pivot4j-core/src/test/java/org/pivot4j/ui/aggregator/CombinedAggregationWith3DimsIT.java index 8efce451..9bd67505 100644 --- a/pivot4j-core/src/test/java/org/pivot4j/ui/aggregator/CombinedAggregationWith3DimsIT.java +++ b/pivot4j-core/src/test/java/org/pivot4j/ui/aggregator/CombinedAggregationWith3DimsIT.java @@ -30,97 +30,98 @@ public class CombinedAggregationWith3DimsIT extends AbstractHtmlTableTestCase { - /** - * @see org.pivot4j.ui.AbstractHtmlTableTestCase#getQueryName() - */ - @Override - protected String getQueryName() { - return "3-dims-combined"; - } - - /** - * @see org.pivot4j.ui.AbstractHtmlTableTestCase#configureRenderer(org.pivot4j.ui.table.TableRenderer) - */ - @Override - protected void configureRenderer(TableRenderer renderer) { - super.configureRenderer(renderer); - - renderer.addAggregator(Axis.ROWS, AggregatorPosition.Hierarchy, - AverageAggregator.NAME); - renderer.addAggregator(Axis.ROWS, AggregatorPosition.Member, - TotalAggregator.NAME); - } - - @Test - public void testAggregation() throws IOException { - HtmlTable table = getTable(); - - // Table content - List bodies = table.getBodies(); - - assertThat("Table body is missing.", bodies, is(notNullValue())); - assertThat("Table body is missing.", bodies.size(), is(equalTo(1))); - - List rows = bodies.get(0).getRows(); - - assertThat("Table content is missing.", rows, is(notNullValue())); - assertThat("Not enough content rows.", rows.size(), is(equalTo(25))); - - // All Products / All Marital Status / All Gender - assertCell(rows, 1, 0, 1, 2, "Average"); - assertCell(rows, 1, 1, 1, 1, "266,773"); - - // All Products / M / All Gender - assertCell(rows, 5, 0, 1, 1, "Total"); - assertCell(rows, 5, 1, 1, 1, "131,796"); - - assertCell(rows, 6, 0, 1, 2, "Average"); - assertCell(rows, 6, 1, 1, 1, "65,898"); - - // All Products / S / All Gender - assertCell(rows, 10, 0, 1, 1, "Total"); - assertCell(rows, 10, 1, 1, 1, "134,977"); - - assertCell(rows, 11, 0, 1, 2, "Average"); - assertCell(rows, 11, 1, 1, 1, "67,488.5"); - - assertCell(rows, 12, 0, 1, 3, "Total"); - assertCell(rows, 12, 1, 1, 1, "266,773"); - - // All Products / All Marital Status / All Gender - assertCell(rows, 13, 0, 1, 4, "Average"); - assertCell(rows, 13, 1, 1, 1, "66,693.25"); - - // Drinks / All Marital Status / All Gender - assertCell(rows, 15, 0, 1, 2, "Average"); - assertCell(rows, 15, 1, 1, 1, "24,597"); - - // Drinks / All Marital Status - assertCell(rows, 16, 0, 1, 4, "Average"); - assertCell(rows, 16, 1, 1, 1, "24,597"); - - // Food / All Marital Status / All Gender - assertCell(rows, 18, 0, 1, 2, "Average"); - assertCell(rows, 18, 1, 1, 1, "191,940"); - - // Food / All Marital Status - assertCell(rows, 19, 0, 1, 4, "Average"); - assertCell(rows, 19, 1, 1, 1, "191,940"); - - // Non-Consumable / All Marital Status / All Gender - assertCell(rows, 21, 0, 1, 2, "Average"); - assertCell(rows, 21, 1, 1, 1, "50,236"); - - // Non-Consumable / All Marital Status - assertCell(rows, 22, 0, 1, 4, "Average"); - assertCell(rows, 22, 1, 1, 1, "50,236"); - - // All Products - assertCell(rows, 23, 0, 1, 5, "Total"); - assertCell(rows, 23, 1, 1, 1, "266,773"); - - // Grand - assertCell(rows, 24, 0, 1, 6, "Average"); - assertCell(rows, 24, 1, 1, 1, "88,924.333"); - } + /** + * @see org.pivot4j.ui.AbstractHtmlTableTestCase#getQueryName() + */ + @Override + protected String getQueryName() { + return "3-dims-combined"; + } + + /** + * @see + * org.pivot4j.ui.AbstractHtmlTableTestCase#configureRenderer(org.pivot4j.ui.table.TableRenderer) + */ + @Override + protected void configureRenderer(TableRenderer renderer) { + super.configureRenderer(renderer); + + renderer.addAggregator(Axis.ROWS, AggregatorPosition.Hierarchy, + AverageAggregator.NAME); + renderer.addAggregator(Axis.ROWS, AggregatorPosition.Member, + TotalAggregator.NAME); + } + + @Test + public void testAggregation() throws IOException { + HtmlTable table = getTable(); + + // Table content + List bodies = table.getBodies(); + + assertThat("Table body is missing.", bodies, is(notNullValue())); + assertThat("Table body is missing.", bodies.size(), is(equalTo(1))); + + List rows = bodies.get(0).getRows(); + + assertThat("Table content is missing.", rows, is(notNullValue())); + assertThat("Not enough content rows.", rows.size(), is(equalTo(25))); + + // All Products / All Marital Status / All Gender + assertCell(rows, 1, 0, 1, 2, "Average"); + assertCell(rows, 1, 1, 1, 1, "266,773"); + + // All Products / M / All Gender + assertCell(rows, 5, 0, 1, 1, "Total"); + assertCell(rows, 5, 1, 1, 1, "131,796"); + + assertCell(rows, 6, 0, 1, 2, "Average"); + assertCell(rows, 6, 1, 1, 1, "65,898"); + + // All Products / S / All Gender + assertCell(rows, 10, 0, 1, 1, "Total"); + assertCell(rows, 10, 1, 1, 1, "134,977"); + + assertCell(rows, 11, 0, 1, 2, "Average"); + assertCell(rows, 11, 1, 1, 1, "67,488.5"); + + assertCell(rows, 12, 0, 1, 3, "Total"); + assertCell(rows, 12, 1, 1, 1, "266,773"); + + // All Products / All Marital Status / All Gender + assertCell(rows, 13, 0, 1, 4, "Average"); + assertCell(rows, 13, 1, 1, 1, "66,693.25"); + + // Drinks / All Marital Status / All Gender + assertCell(rows, 15, 0, 1, 2, "Average"); + assertCell(rows, 15, 1, 1, 1, "24,597"); + + // Drinks / All Marital Status + assertCell(rows, 16, 0, 1, 4, "Average"); + assertCell(rows, 16, 1, 1, 1, "24,597"); + + // Food / All Marital Status / All Gender + assertCell(rows, 18, 0, 1, 2, "Average"); + assertCell(rows, 18, 1, 1, 1, "191,940"); + + // Food / All Marital Status + assertCell(rows, 19, 0, 1, 4, "Average"); + assertCell(rows, 19, 1, 1, 1, "191,940"); + + // Non-Consumable / All Marital Status / All Gender + assertCell(rows, 21, 0, 1, 2, "Average"); + assertCell(rows, 21, 1, 1, 1, "50,236"); + + // Non-Consumable / All Marital Status + assertCell(rows, 22, 0, 1, 4, "Average"); + assertCell(rows, 22, 1, 1, 1, "50,236"); + + // All Products + assertCell(rows, 23, 0, 1, 5, "Total"); + assertCell(rows, 23, 1, 1, 1, "266,773"); + + // Grand + assertCell(rows, 24, 0, 1, 6, "Average"); + assertCell(rows, 24, 1, 1, 1, "88,924.333"); + } } diff --git a/pivot4j-core/src/test/java/org/pivot4j/ui/aggregator/ComplexAggregationIT.java b/pivot4j-core/src/test/java/org/pivot4j/ui/aggregator/ComplexAggregationIT.java index c550ea18..7ce65684 100644 --- a/pivot4j-core/src/test/java/org/pivot4j/ui/aggregator/ComplexAggregationIT.java +++ b/pivot4j-core/src/test/java/org/pivot4j/ui/aggregator/ComplexAggregationIT.java @@ -32,172 +32,173 @@ public class ComplexAggregationIT extends AbstractHtmlTableTestCase { - /** - * @see org.pivot4j.ui.AbstractHtmlTableTestCase#getQueryName() - */ - @Override - protected String getQueryName() { - return "complex"; - } - - /** - * @see org.pivot4j.ui.AbstractHtmlTableTestCase#configureRenderer(org.pivot4j.ui.table.TableRenderer) - */ - @Override - protected void configureRenderer(TableRenderer renderer) { - super.configureRenderer(renderer); - - renderer.addAggregator(Axis.ROWS, AggregatorPosition.Grand, - MinimumAggregator.NAME); - renderer.addAggregator(Axis.ROWS, AggregatorPosition.Hierarchy, - TotalAggregator.NAME); - renderer.addAggregator(Axis.ROWS, AggregatorPosition.Member, - AverageAggregator.NAME); - - renderer.addAggregator(Axis.COLUMNS, AggregatorPosition.Grand, - MinimumAggregator.NAME); - renderer.addAggregator(Axis.COLUMNS, AggregatorPosition.Hierarchy, - TotalAggregator.NAME); - renderer.addAggregator(Axis.COLUMNS, AggregatorPosition.Member, - AverageAggregator.NAME); - } - - @Test - public void testAggregation() throws IOException { - HtmlTable table = getTable(); - - HtmlTableHeader header = table.getHeader(); - - List rows = header.getRows(); - - assertThat("Table header is missing.", rows, is(notNullValue())); - assertThat("Not enough column header rows.", rows.size(), - is(equalTo(9))); - - // Column headers - assertCell(rows, 0, 0, 7, 7, null); - assertCell(rows, 0, 1, 1, 45, "Time"); - assertCell(rows, 1, 0, 1, 39, "1997"); - assertCell(rows, 1, 1, 6, 3, "Total"); - assertCell(rows, 1, 2, 6, 3, "Minimum"); - assertCell(rows, 2, 0, 2, 9, "Q1"); - assertCell(rows, 2, 1, 2, 9, "Q2"); - assertCell(rows, 2, 2, 1, 21, "Q2"); - - assertCell(rows, 3, 0, 1, 9, "5"); - assertCell(rows, 3, 1, 1, 9, "6"); - - for (int i = 0; i < 3; i++) { - assertCell(rows, 4, i, 1, 9, "Gender"); - } - - assertCell(rows, 5, 0, 1, 6, "All Gender"); - assertCell(rows, 5, 1, 2, 3, "Total"); - - for (int i = 0; i < 3; i++) { - assertCell(rows, 5, (i * 2) + 2, 1, 6, "All Gender"); - assertCell(rows, 5, (i * 2) + 3, 2, 3, "Total"); - } - - for (int i = 0; i < 4; i++) { - assertCell(rows, 6, (i * 2), 1, 3, "F"); - assertCell(rows, 6, (i * 2) + 1, 1, 3, "M"); - } - - assertCell(rows, 7, 0, 1, 2, "Promotion Media"); - assertCell(rows, 7, 1, 1, 2, "Marital Status"); - assertCell(rows, 7, 2, 1, 3, "Product"); - - for (int i = 3; i < 16; i++) { - assertCell(rows, 7, i, 1, 3, "Measures"); - } - - assertCell(rows, 8, 0, 1, 1, "(All)"); - assertCell(rows, 8, 1, 1, 1, "Media Type"); - assertCell(rows, 8, 2, 1, 1, "(All)"); - assertCell(rows, 8, 3, 1, 1, "Marital Status"); - assertCell(rows, 8, 4, 1, 1, "(All)"); - assertCell(rows, 8, 5, 1, 1, "Product Family"); - assertCell(rows, 8, 6, 1, 1, "Product Department"); - - for (int i = 0; i < 13; i++) { - assertCell(rows, 8, (i * 3) + 7, 1, 1, "Store Sales"); - assertCell(rows, 8, (i * 3) + 8, 1, 1, "Store Cost"); - assertCell(rows, 8, (i * 3) + 9, 1, 1, "Unit Sales"); - } - - // Table content - List bodies = table.getBodies(); - - assertThat("Table body is missing.", bodies, is(notNullValue())); - assertThat("Table body is missing.", bodies.size(), is(equalTo(1))); - - rows = bodies.get(0).getRows(); - - assertThat("Table content is missing.", rows, is(notNullValue())); - assertThat("Not enough content rows.", rows.size(), is(equalTo(51))); - - assertCell(rows, 0, 0, 49, 1, "All Media"); - assertCell(rows, 0, 1, 25, 1, "Bulk Mail"); - assertCell(rows, 0, 2, 24, 1, "All Marital Status"); - assertCell(rows, 0, 3, 12, 1, "M"); - assertCell(rows, 0, 4, 11, 1, "All Products"); - assertCell(rows, 0, 5, 4, 1, "Drink"); - assertCell(rows, 0, 6, 1, 1, "Alcoholic Beverages"); - - assertCell(rows, 1, 0, 1, 1, "Beverages"); - assertCell(rows, 2, 0, 1, 1, "Dairy"); - assertCell(rows, 3, 0, 1, 1, "Average"); - assertCell(rows, 4, 0, 1, 2, "Food"); - - assertCell(rows, 5, 0, 4, 1, "Food"); - assertCell(rows, 5, 1, 1, 1, "Dairy"); - assertCell(rows, 6, 0, 1, 1, "Eggs"); - assertCell(rows, 7, 0, 1, 1, "Frozen Foods"); - assertCell(rows, 8, 0, 1, 1, "Average"); - assertCell(rows, 9, 0, 1, 2, "Non-Consumable"); - - // Member total title - assertCell(rows, 10, 0, 1, 1, "Drink"); - assertCell(rows, 10, 1, 1, 1, "Average"); - assertCell(rows, 11, 0, 1, 3, "Total"); - - // Hierarchy total title - assertCell(rows, 23, 0, 1, 3, "Total"); - - // Axis total title - assertCell(rows, 50, 0, 1, 7, "Minimum"); - - // Row axis member aggregation - // (Bulk Mail, M, Food, Average / Q1, F, Store Sales) - assertCell(rows, 8, 7, 1, 1, "26.00"); - - // Row axis hierarchy aggregation - // (Daily Paper, S, Total / Q1, F, Store Sales) - assertCell(rows, 47, 1, 1, 1, "887.15"); - - // Row axis hierarchy aggregation - // (Daily Paper, Total / Q1, F, Store Sales) - assertCell(rows, 48, 1, 1, 1, "2,052.52"); - - // Row axis aggregation - // (Minimum / Q1, F, Store Sales) - assertCell(rows, 50, 1, 1, 1, "2.26"); - - // Column axis member aggregation - // (Bulk Mail, M, Food, Frozen Foods / Q2, 6, Average, Unit Sales) - assertCell(rows, 7, 39, 1, 1, "11"); - - // Column axis hierarchy aggregation - // (Daily Paper, S, Drink, Average / Q2, Total, Store Cost) - assertCell(rows, 40, 17, 1, 1, "7.94"); - - // Column axis hierarchy aggregation - // (Bulk Mail, M, Drink, Alcoholic Beverages / Q2, 6, Total, Store Cost) - assertCell(rows, 0, 41, 1, 1, "13.88"); - - // Column axis aggregation - // (Bulk Mail, M, Food, Frozen Foods / Minimum, Unit Sales) - assertCell(rows, 7, 45, 1, 1, "8"); - } + /** + * @see org.pivot4j.ui.AbstractHtmlTableTestCase#getQueryName() + */ + @Override + protected String getQueryName() { + return "complex"; + } + + /** + * @see + * org.pivot4j.ui.AbstractHtmlTableTestCase#configureRenderer(org.pivot4j.ui.table.TableRenderer) + */ + @Override + protected void configureRenderer(TableRenderer renderer) { + super.configureRenderer(renderer); + + renderer.addAggregator(Axis.ROWS, AggregatorPosition.Grand, + MinimumAggregator.NAME); + renderer.addAggregator(Axis.ROWS, AggregatorPosition.Hierarchy, + TotalAggregator.NAME); + renderer.addAggregator(Axis.ROWS, AggregatorPosition.Member, + AverageAggregator.NAME); + + renderer.addAggregator(Axis.COLUMNS, AggregatorPosition.Grand, + MinimumAggregator.NAME); + renderer.addAggregator(Axis.COLUMNS, AggregatorPosition.Hierarchy, + TotalAggregator.NAME); + renderer.addAggregator(Axis.COLUMNS, AggregatorPosition.Member, + AverageAggregator.NAME); + } + + @Test + public void testAggregation() throws IOException { + HtmlTable table = getTable(); + + HtmlTableHeader header = table.getHeader(); + + List rows = header.getRows(); + + assertThat("Table header is missing.", rows, is(notNullValue())); + assertThat("Not enough column header rows.", rows.size(), + is(equalTo(9))); + + // Column headers + assertCell(rows, 0, 0, 7, 7, null); + assertCell(rows, 0, 1, 1, 45, "Time"); + assertCell(rows, 1, 0, 1, 39, "1997"); + assertCell(rows, 1, 1, 6, 3, "Total"); + assertCell(rows, 1, 2, 6, 3, "Minimum"); + assertCell(rows, 2, 0, 2, 9, "Q1"); + assertCell(rows, 2, 1, 2, 9, "Q2"); + assertCell(rows, 2, 2, 1, 21, "Q2"); + + assertCell(rows, 3, 0, 1, 9, "5"); + assertCell(rows, 3, 1, 1, 9, "6"); + + for (int i = 0; i < 3; i++) { + assertCell(rows, 4, i, 1, 9, "Gender"); + } + + assertCell(rows, 5, 0, 1, 6, "All Gender"); + assertCell(rows, 5, 1, 2, 3, "Total"); + + for (int i = 0; i < 3; i++) { + assertCell(rows, 5, (i * 2) + 2, 1, 6, "All Gender"); + assertCell(rows, 5, (i * 2) + 3, 2, 3, "Total"); + } + + for (int i = 0; i < 4; i++) { + assertCell(rows, 6, (i * 2), 1, 3, "F"); + assertCell(rows, 6, (i * 2) + 1, 1, 3, "M"); + } + + assertCell(rows, 7, 0, 1, 2, "Promotion Media"); + assertCell(rows, 7, 1, 1, 2, "Marital Status"); + assertCell(rows, 7, 2, 1, 3, "Product"); + + for (int i = 3; i < 16; i++) { + assertCell(rows, 7, i, 1, 3, "Measures"); + } + + assertCell(rows, 8, 0, 1, 1, "(All)"); + assertCell(rows, 8, 1, 1, 1, "Media Type"); + assertCell(rows, 8, 2, 1, 1, "(All)"); + assertCell(rows, 8, 3, 1, 1, "Marital Status"); + assertCell(rows, 8, 4, 1, 1, "(All)"); + assertCell(rows, 8, 5, 1, 1, "Product Family"); + assertCell(rows, 8, 6, 1, 1, "Product Department"); + + for (int i = 0; i < 13; i++) { + assertCell(rows, 8, (i * 3) + 7, 1, 1, "Store Sales"); + assertCell(rows, 8, (i * 3) + 8, 1, 1, "Store Cost"); + assertCell(rows, 8, (i * 3) + 9, 1, 1, "Unit Sales"); + } + + // Table content + List bodies = table.getBodies(); + + assertThat("Table body is missing.", bodies, is(notNullValue())); + assertThat("Table body is missing.", bodies.size(), is(equalTo(1))); + + rows = bodies.get(0).getRows(); + + assertThat("Table content is missing.", rows, is(notNullValue())); + assertThat("Not enough content rows.", rows.size(), is(equalTo(51))); + + assertCell(rows, 0, 0, 49, 1, "All Media"); + assertCell(rows, 0, 1, 25, 1, "Bulk Mail"); + assertCell(rows, 0, 2, 24, 1, "All Marital Status"); + assertCell(rows, 0, 3, 12, 1, "M"); + assertCell(rows, 0, 4, 11, 1, "All Products"); + assertCell(rows, 0, 5, 4, 1, "Drink"); + assertCell(rows, 0, 6, 1, 1, "Alcoholic Beverages"); + + assertCell(rows, 1, 0, 1, 1, "Beverages"); + assertCell(rows, 2, 0, 1, 1, "Dairy"); + assertCell(rows, 3, 0, 1, 1, "Average"); + assertCell(rows, 4, 0, 1, 2, "Food"); + + assertCell(rows, 5, 0, 4, 1, "Food"); + assertCell(rows, 5, 1, 1, 1, "Dairy"); + assertCell(rows, 6, 0, 1, 1, "Eggs"); + assertCell(rows, 7, 0, 1, 1, "Frozen Foods"); + assertCell(rows, 8, 0, 1, 1, "Average"); + assertCell(rows, 9, 0, 1, 2, "Non-Consumable"); + + // Member total title + assertCell(rows, 10, 0, 1, 1, "Drink"); + assertCell(rows, 10, 1, 1, 1, "Average"); + assertCell(rows, 11, 0, 1, 3, "Total"); + + // Hierarchy total title + assertCell(rows, 23, 0, 1, 3, "Total"); + + // Axis total title + assertCell(rows, 50, 0, 1, 7, "Minimum"); + + // Row axis member aggregation + // (Bulk Mail, M, Food, Average / Q1, F, Store Sales) + assertCell(rows, 8, 7, 1, 1, "26.00"); + + // Row axis hierarchy aggregation + // (Daily Paper, S, Total / Q1, F, Store Sales) + assertCell(rows, 47, 1, 1, 1, "887.15"); + + // Row axis hierarchy aggregation + // (Daily Paper, Total / Q1, F, Store Sales) + assertCell(rows, 48, 1, 1, 1, "2,052.52"); + + // Row axis aggregation + // (Minimum / Q1, F, Store Sales) + assertCell(rows, 50, 1, 1, 1, "2.26"); + + // Column axis member aggregation + // (Bulk Mail, M, Food, Frozen Foods / Q2, 6, Average, Unit Sales) + assertCell(rows, 7, 39, 1, 1, "11"); + + // Column axis hierarchy aggregation + // (Daily Paper, S, Drink, Average / Q2, Total, Store Cost) + assertCell(rows, 40, 17, 1, 1, "7.94"); + + // Column axis hierarchy aggregation + // (Bulk Mail, M, Drink, Alcoholic Beverages / Q2, 6, Total, Store Cost) + assertCell(rows, 0, 41, 1, 1, "13.88"); + + // Column axis aggregation + // (Bulk Mail, M, Food, Frozen Foods / Minimum, Unit Sales) + assertCell(rows, 7, 45, 1, 1, "8"); + } } diff --git a/pivot4j-core/src/test/java/org/pivot4j/ui/aggregator/HierarchyAggregationWithAllMemberIT.java b/pivot4j-core/src/test/java/org/pivot4j/ui/aggregator/HierarchyAggregationWithAllMemberIT.java index 1c9f9960..b2f683d8 100644 --- a/pivot4j-core/src/test/java/org/pivot4j/ui/aggregator/HierarchyAggregationWithAllMemberIT.java +++ b/pivot4j-core/src/test/java/org/pivot4j/ui/aggregator/HierarchyAggregationWithAllMemberIT.java @@ -28,68 +28,69 @@ import com.gargoylesoftware.htmlunit.html.HtmlTableRow; public class HierarchyAggregationWithAllMemberIT extends - AbstractHtmlTableTestCase { - - /** - * @see org.pivot4j.ui.AbstractHtmlTableTestCase#getQueryName() - */ - @Override - protected String getQueryName() { - return "hierarchy-with-all"; - } - - /** - * @see org.pivot4j.ui.AbstractHtmlTableTestCase#configureRenderer(org.pivot4j.ui.table.TableRenderer) - */ - @Override - protected void configureRenderer(TableRenderer renderer) { - super.configureRenderer(renderer); - - renderer.addAggregator(Axis.ROWS, AggregatorPosition.Hierarchy, - TotalAggregator.NAME); - } - - @Test - public void testAggregation() throws IOException { - HtmlTable table = getTable(); - - // Table content - List bodies = table.getBodies(); - - assertThat("Table body is missing.", bodies, is(notNullValue())); - assertThat("Table body is missing.", bodies.size(), is(equalTo(1))); - - List rows = bodies.get(0).getRows(); - - assertThat("Table content is missing.", rows, is(notNullValue())); - assertThat("Not enough content rows.", rows.size(), is(equalTo(15))); - - // All Products - assertCell(rows, 3, 0, 1, 2, "Total"); - assertCell(rows, 3, 1, 1, 1, "266,773"); - - // All Products / Drinks - assertCell(rows, 5, 0, 1, 2, "Total"); - assertCell(rows, 5, 1, 1, 1, "24,597"); - - // All Products / Drinks - assertCell(rows, 5, 0, 1, 2, "Total"); - assertCell(rows, 5, 1, 1, 1, "24,597"); - - // All Products / Food - assertCell(rows, 9, 0, 1, 2, "Total"); - assertCell(rows, 9, 1, 1, 1, "191,940"); - - // All Products / Non-Consumable - assertCell(rows, 13, 0, 1, 2, "Total"); - assertCell(rows, 13, 1, 1, 1, "50,236"); - - // All Products / Non-Consumable - assertCell(rows, 13, 0, 1, 2, "Total"); - assertCell(rows, 13, 1, 1, 1, "50,236"); - - // Grand - assertCell(rows, 14, 0, 1, 4, "Total"); - assertCell(rows, 14, 1, 1, 1, "266,773"); - } + AbstractHtmlTableTestCase { + + /** + * @see org.pivot4j.ui.AbstractHtmlTableTestCase#getQueryName() + */ + @Override + protected String getQueryName() { + return "hierarchy-with-all"; + } + + /** + * @see + * org.pivot4j.ui.AbstractHtmlTableTestCase#configureRenderer(org.pivot4j.ui.table.TableRenderer) + */ + @Override + protected void configureRenderer(TableRenderer renderer) { + super.configureRenderer(renderer); + + renderer.addAggregator(Axis.ROWS, AggregatorPosition.Hierarchy, + TotalAggregator.NAME); + } + + @Test + public void testAggregation() throws IOException { + HtmlTable table = getTable(); + + // Table content + List bodies = table.getBodies(); + + assertThat("Table body is missing.", bodies, is(notNullValue())); + assertThat("Table body is missing.", bodies.size(), is(equalTo(1))); + + List rows = bodies.get(0).getRows(); + + assertThat("Table content is missing.", rows, is(notNullValue())); + assertThat("Not enough content rows.", rows.size(), is(equalTo(15))); + + // All Products + assertCell(rows, 3, 0, 1, 2, "Total"); + assertCell(rows, 3, 1, 1, 1, "266,773"); + + // All Products / Drinks + assertCell(rows, 5, 0, 1, 2, "Total"); + assertCell(rows, 5, 1, 1, 1, "24,597"); + + // All Products / Drinks + assertCell(rows, 5, 0, 1, 2, "Total"); + assertCell(rows, 5, 1, 1, 1, "24,597"); + + // All Products / Food + assertCell(rows, 9, 0, 1, 2, "Total"); + assertCell(rows, 9, 1, 1, 1, "191,940"); + + // All Products / Non-Consumable + assertCell(rows, 13, 0, 1, 2, "Total"); + assertCell(rows, 13, 1, 1, 1, "50,236"); + + // All Products / Non-Consumable + assertCell(rows, 13, 0, 1, 2, "Total"); + assertCell(rows, 13, 1, 1, 1, "50,236"); + + // Grand + assertCell(rows, 14, 0, 1, 4, "Total"); + assertCell(rows, 14, 1, 1, 1, "266,773"); + } } diff --git a/pivot4j-core/src/test/java/org/pivot4j/ui/aggregator/MemberAggregationWithAllMemberIT.java b/pivot4j-core/src/test/java/org/pivot4j/ui/aggregator/MemberAggregationWithAllMemberIT.java index f72cf096..afb7f253 100644 --- a/pivot4j-core/src/test/java/org/pivot4j/ui/aggregator/MemberAggregationWithAllMemberIT.java +++ b/pivot4j-core/src/test/java/org/pivot4j/ui/aggregator/MemberAggregationWithAllMemberIT.java @@ -29,56 +29,57 @@ public class MemberAggregationWithAllMemberIT extends AbstractHtmlTableTestCase { - /** - * @see org.pivot4j.ui.AbstractHtmlTableTestCase#getQueryName() - */ - @Override - protected String getQueryName() { - return "member-with-all"; - } - - /** - * @param renderer - * @see org.pivot4j.ui.AbstractHtmlTableTestCase#configureRenderer(org.pivot4j.ui.table.TableRenderer) - */ - @Override - protected void configureRenderer(TableRenderer renderer) { - super.configureRenderer(renderer); - - renderer.setShowParentMembers(false); - renderer.addAggregator(Axis.ROWS, AggregatorPosition.Member, - TotalAggregator.NAME); - } - - @Test - public void testAggregation() throws IOException { - HtmlTable table = getTable(); - - // Table content - List bodies = table.getBodies(); - - assertThat("Table body is missing.", bodies, is(notNullValue())); - assertThat("Table body is missing.", bodies.size(), is(equalTo(1))); - - List rows = bodies.get(0).getRows(); - - assertThat("Table content is missing.", rows, is(notNullValue())); - assertThat("Not enough content rows.", rows.size(), is(equalTo(16))); - - // All Products / Alcoholic Beverages - assertCell(rows, 4, 0, 1, 1, "Total"); - assertCell(rows, 4, 1, 1, 1, "6,838"); - - // All Products / Beverages - assertCell(rows, 10, 0, 1, 1, "Total"); - assertCell(rows, 10, 1, 1, 1, "13,573"); - - // All Products / Drinks - assertCell(rows, 12, 0, 1, 1, "Total"); - assertCell(rows, 12, 1, 1, 1, "24,597"); - - // All Products / Drinks - assertCell(rows, 15, 0, 1, 1, "Total"); - assertCell(rows, 15, 1, 1, 1, "266,773"); - } + /** + * @see org.pivot4j.ui.AbstractHtmlTableTestCase#getQueryName() + */ + @Override + protected String getQueryName() { + return "member-with-all"; + } + + /** + * @param renderer + * @see + * org.pivot4j.ui.AbstractHtmlTableTestCase#configureRenderer(org.pivot4j.ui.table.TableRenderer) + */ + @Override + protected void configureRenderer(TableRenderer renderer) { + super.configureRenderer(renderer); + + renderer.setShowParentMembers(false); + renderer.addAggregator(Axis.ROWS, AggregatorPosition.Member, + TotalAggregator.NAME); + } + + @Test + public void testAggregation() throws IOException { + HtmlTable table = getTable(); + + // Table content + List bodies = table.getBodies(); + + assertThat("Table body is missing.", bodies, is(notNullValue())); + assertThat("Table body is missing.", bodies.size(), is(equalTo(1))); + + List rows = bodies.get(0).getRows(); + + assertThat("Table content is missing.", rows, is(notNullValue())); + assertThat("Not enough content rows.", rows.size(), is(equalTo(16))); + + // All Products / Alcoholic Beverages + assertCell(rows, 4, 0, 1, 1, "Total"); + assertCell(rows, 4, 1, 1, 1, "6,838"); + + // All Products / Beverages + assertCell(rows, 10, 0, 1, 1, "Total"); + assertCell(rows, 10, 1, 1, 1, "13,573"); + + // All Products / Drinks + assertCell(rows, 12, 0, 1, 1, "Total"); + assertCell(rows, 12, 1, 1, 1, "24,597"); + + // All Products / Drinks + assertCell(rows, 15, 0, 1, 1, "Total"); + assertCell(rows, 15, 1, 1, 1, "266,773"); + } } diff --git a/pivot4j-core/src/test/java/org/pivot4j/ui/aggregator/SimpleAggregationIT.java b/pivot4j-core/src/test/java/org/pivot4j/ui/aggregator/SimpleAggregationIT.java index 70cee244..424c5f8f 100644 --- a/pivot4j-core/src/test/java/org/pivot4j/ui/aggregator/SimpleAggregationIT.java +++ b/pivot4j-core/src/test/java/org/pivot4j/ui/aggregator/SimpleAggregationIT.java @@ -30,73 +30,74 @@ public class SimpleAggregationIT extends AbstractHtmlTableTestCase { - /** - * @see org.pivot4j.ui.AbstractHtmlTableTestCase#getQueryName() - */ - @Override - protected String getQueryName() { - return "simple"; - } - - /** - * @param renderer - * @see org.pivot4j.ui.AbstractHtmlTableTestCase#configureRenderer(org.pivot4j.ui.table.TableRenderer) - */ - @Override - protected void configureRenderer(TableRenderer renderer) { - super.configureRenderer(renderer); - - renderer.setShowParentMembers(false); - - renderer.addAggregator(Axis.ROWS, AggregatorPosition.Grand, - TotalAggregator.NAME); - renderer.addAggregator(Axis.COLUMNS, AggregatorPosition.Grand, - TotalAggregator.NAME); - } - - @Test - public void testAggregation() throws IOException { - HtmlTable table = getTable(); - - HtmlTableHeader header = table.getHeader(); - - List rows = header.getRows(); - - assertThat("Table header is missing.", rows, is(notNullValue())); - assertThat("Not enough column header rows.", rows.size(), - is(equalTo(3))); - - assertCell(rows, 0, 0, 2, 1, null); - assertCell(rows, 0, 1, 1, 4, "Measures"); - - assertCell(rows, 1, 0, 2, 1, "Store Cost"); - assertCell(rows, 1, 1, 2, 1, "Unit Sales"); - assertCell(rows, 1, 2, 1, 2, "Total"); - - assertCell(rows, 2, 0, 1, 1, "Product"); - assertCell(rows, 2, 1, 1, 1, "Store Cost"); - assertCell(rows, 2, 2, 1, 1, "Unit Sales"); - - List bodies = table.getBodies(); - - assertThat("Table body is missing.", bodies, is(notNullValue())); - assertThat("Table body is missing.", bodies.size(), is(equalTo(1))); - - rows = bodies.get(0).getRows(); - - assertThat("Table content is missing.", rows, is(notNullValue())); - assertThat("Not enough content rows.", rows.size(), is(equalTo(2))); - - assertCell(rows, 0, 0, 1, 1, "All Products"); - assertCell(rows, 0, 1, 1, 1, "225,627.23"); - assertCell(rows, 0, 2, 1, 1, "266,773"); - assertCell(rows, 0, 3, 1, 1, "225,627.23"); - assertCell(rows, 0, 4, 1, 1, "266,773"); - - assertCell(rows, 1, 0, 1, 1, "Total"); - assertCell(rows, 1, 1, 1, 1, "225,627.23"); - assertCell(rows, 1, 2, 1, 1, "266,773"); - assertCell(rows, 1, 3, 1, 1, "225,627.23"); - assertCell(rows, 1, 4, 1, 1, "266,773"); - } + /** + * @see org.pivot4j.ui.AbstractHtmlTableTestCase#getQueryName() + */ + @Override + protected String getQueryName() { + return "simple"; + } + + /** + * @param renderer + * @see + * org.pivot4j.ui.AbstractHtmlTableTestCase#configureRenderer(org.pivot4j.ui.table.TableRenderer) + */ + @Override + protected void configureRenderer(TableRenderer renderer) { + super.configureRenderer(renderer); + + renderer.setShowParentMembers(false); + + renderer.addAggregator(Axis.ROWS, AggregatorPosition.Grand, + TotalAggregator.NAME); + renderer.addAggregator(Axis.COLUMNS, AggregatorPosition.Grand, + TotalAggregator.NAME); + } + + @Test + public void testAggregation() throws IOException { + HtmlTable table = getTable(); + + HtmlTableHeader header = table.getHeader(); + + List rows = header.getRows(); + + assertThat("Table header is missing.", rows, is(notNullValue())); + assertThat("Not enough column header rows.", rows.size(), + is(equalTo(3))); + + assertCell(rows, 0, 0, 2, 1, null); + assertCell(rows, 0, 1, 1, 4, "Measures"); + + assertCell(rows, 1, 0, 2, 1, "Store Cost"); + assertCell(rows, 1, 1, 2, 1, "Unit Sales"); + assertCell(rows, 1, 2, 1, 2, "Total"); + + assertCell(rows, 2, 0, 1, 1, "Product"); + assertCell(rows, 2, 1, 1, 1, "Store Cost"); + assertCell(rows, 2, 2, 1, 1, "Unit Sales"); + + List bodies = table.getBodies(); + + assertThat("Table body is missing.", bodies, is(notNullValue())); + assertThat("Table body is missing.", bodies.size(), is(equalTo(1))); + + rows = bodies.get(0).getRows(); + + assertThat("Table content is missing.", rows, is(notNullValue())); + assertThat("Not enough content rows.", rows.size(), is(equalTo(2))); + + assertCell(rows, 0, 0, 1, 1, "All Products"); + assertCell(rows, 0, 1, 1, 1, "225,627.23"); + assertCell(rows, 0, 2, 1, 1, "266,773"); + assertCell(rows, 0, 3, 1, 1, "225,627.23"); + assertCell(rows, 0, 4, 1, 1, "266,773"); + + assertCell(rows, 1, 0, 1, 1, "Total"); + assertCell(rows, 1, 1, 1, 1, "225,627.23"); + assertCell(rows, 1, 2, 1, 1, "266,773"); + assertCell(rows, 1, 3, 1, 1, "225,627.23"); + assertCell(rows, 1, 4, 1, 1, "266,773"); + } } diff --git a/pivot4j-core/src/test/java/org/pivot4j/ui/condition/AbstractConditionTest.java b/pivot4j-core/src/test/java/org/pivot4j/ui/condition/AbstractConditionTest.java index 2ebc51cf..c9170fbd 100644 --- a/pivot4j-core/src/test/java/org/pivot4j/ui/condition/AbstractConditionTest.java +++ b/pivot4j-core/src/test/java/org/pivot4j/ui/condition/AbstractConditionTest.java @@ -21,73 +21,73 @@ public abstract class AbstractConditionTest extends AbstractMockRenderTestCase { - protected static ConditionFactory conditionFactory = new DefaultConditionFactory() { + protected static ConditionFactory conditionFactory = new DefaultConditionFactory() { - @Override - public List getAvailableConditions() { - List conditions = super.getAvailableConditions(); - conditions.add("TRUE"); - conditions.add("FALSE"); + @Override + public List getAvailableConditions() { + List conditions = super.getAvailableConditions(); + conditions.add("TRUE"); + conditions.add("FALSE"); - return conditions; - } + return conditions; + } - @Override - public Condition createCondition(String name) { - if (name.equals("TRUE")) { - return TestCondition.TRUE; - } else if (name.equals("FALSE")) { - return TestCondition.FALSE; - } + @Override + public Condition createCondition(String name) { + if (name.equals("TRUE")) { + return TestCondition.TRUE; + } else if (name.equals("FALSE")) { + return TestCondition.FALSE; + } - return super.createCondition(name); - } - }; + return super.createCondition(name); + } + }; - static class TestCondition extends AbstractCondition { + static class TestCondition extends AbstractCondition { - private boolean result; + private boolean result; - static Condition TRUE = new TestCondition(true); + static Condition TRUE = new TestCondition(true); - static Condition FALSE = new TestCondition(false); + static Condition FALSE = new TestCondition(false); - private TestCondition(boolean result) { - super(conditionFactory); + private TestCondition(boolean result) { + super(conditionFactory); - this.result = result; - } + this.result = result; + } - @Override - public String getName() { - return result ? "TRUE" : "FALSE"; - } + @Override + public String getName() { + return result ? "TRUE" : "FALSE"; + } - @Override - public boolean matches(RenderContext context) { - return result; - } + @Override + public boolean matches(RenderContext context) { + return result; + } - @Override - public Serializable saveState() { - return result; - } + @Override + public Serializable saveState() { + return result; + } - @Override - public void restoreState(Serializable state) { - this.result = (Boolean) state; - } + @Override + public void restoreState(Serializable state) { + this.result = (Boolean) state; + } - @Override - public void saveSettings(HierarchicalConfiguration configuration) { - super.saveSettings(configuration); + @Override + public void saveSettings(HierarchicalConfiguration configuration) { + super.saveSettings(configuration); - configuration.setProperty("[@result]", result); - } + configuration.setProperty("[@result]", result); + } - @Override - public void restoreSettings(HierarchicalConfiguration configuration) { - this.result = configuration.getBoolean("[@result]"); - } - } + @Override + public void restoreSettings(HierarchicalConfiguration configuration) { + this.result = configuration.getBoolean("[@result]"); + } + } } diff --git a/pivot4j-core/src/test/java/org/pivot4j/ui/condition/AndConditionTest.java b/pivot4j-core/src/test/java/org/pivot4j/ui/condition/AndConditionTest.java index a4516588..e01fcb45 100644 --- a/pivot4j-core/src/test/java/org/pivot4j/ui/condition/AndConditionTest.java +++ b/pivot4j-core/src/test/java/org/pivot4j/ui/condition/AndConditionTest.java @@ -23,85 +23,85 @@ public class AndConditionTest extends AbstractConditionTest { - @Test(expected = IllegalStateException.class) - public void testEmptyCondition() { - RenderContext context = createDummyRenderContext(); + @Test(expected = IllegalStateException.class) + public void testEmptyCondition() { + RenderContext context = createDummyRenderContext(); - AndCondition and = new AndCondition(conditionFactory); - and.matches(context); - } + AndCondition and = new AndCondition(conditionFactory); + and.matches(context); + } - @Test - public void testCondition() { - RenderContext context = createDummyRenderContext(); + @Test + public void testCondition() { + RenderContext context = createDummyRenderContext(); - AndCondition and = new AndCondition(conditionFactory); + AndCondition and = new AndCondition(conditionFactory); - and.setSubConditions(Arrays.asList(TestCondition.TRUE, - TestCondition.TRUE)); - assertThat("'true && true' should be true.", and.matches(context), - is(true)); + and.setSubConditions(Arrays.asList(TestCondition.TRUE, + TestCondition.TRUE)); + assertThat("'true && true' should be true.", and.matches(context), + is(true)); - and.setSubConditions(Arrays.asList(TestCondition.TRUE, - TestCondition.FALSE)); - assertThat("'true && false' should be false.", and.matches(context), - is(false)); + and.setSubConditions(Arrays.asList(TestCondition.TRUE, + TestCondition.FALSE)); + assertThat("'true && false' should be false.", and.matches(context), + is(false)); - and.setSubConditions(Arrays.asList(TestCondition.TRUE)); - assertThat("'true' should be true.", and.matches(context), is(true)); + and.setSubConditions(Arrays.asList(TestCondition.TRUE)); + assertThat("'true' should be true.", and.matches(context), is(true)); - and.setSubConditions(Arrays.asList(TestCondition.FALSE, - TestCondition.FALSE, TestCondition.FALSE)); - assertThat("'false && false && false' should be false.", - and.matches(context), is(false)); - } + and.setSubConditions(Arrays.asList(TestCondition.FALSE, + TestCondition.FALSE, TestCondition.FALSE)); + assertThat("'false && false && false' should be false.", + and.matches(context), is(false)); + } - @Test - public void testStateManagement() { - RenderContext context = createDummyRenderContext(); + @Test + public void testStateManagement() { + RenderContext context = createDummyRenderContext(); - AndCondition and = new AndCondition(conditionFactory); - and.setSubConditions(Arrays.asList(TestCondition.TRUE, - TestCondition.TRUE)); + AndCondition and = new AndCondition(conditionFactory); + and.setSubConditions(Arrays.asList(TestCondition.TRUE, + TestCondition.TRUE)); - Serializable state = and.saveState(); + Serializable state = and.saveState(); - and = new AndCondition(conditionFactory); - and.restoreState(state); + and = new AndCondition(conditionFactory); + and.restoreState(state); - assertThat("Sub conditions should not be null.", - and.getSubConditions(), is(notNullValue())); - assertThat("Sub condition count should be 2.", and.getSubConditions() - .size(), is(2)); - assertThat("'true && true' should be true.", and.matches(context), - is(true)); - } + assertThat("Sub conditions should not be null.", + and.getSubConditions(), is(notNullValue())); + assertThat("Sub condition count should be 2.", and.getSubConditions() + .size(), is(2)); + assertThat("'true && true' should be true.", and.matches(context), + is(true)); + } - @Test - public void testSettingsManagement() throws ConfigurationException { - RenderContext context = createDummyRenderContext(); + @Test + public void testSettingsManagement() throws ConfigurationException { + RenderContext context = createDummyRenderContext(); - AndCondition and = new AndCondition(conditionFactory); - and.setSubConditions(Arrays.asList(TestCondition.TRUE, - TestCondition.TRUE)); + AndCondition and = new AndCondition(conditionFactory); + and.setSubConditions(Arrays.asList(TestCondition.TRUE, + TestCondition.TRUE)); - XMLConfiguration configuration = new XMLConfiguration(); - configuration.setRootElementName("condition"); + XMLConfiguration configuration = new XMLConfiguration(); + configuration.setRootElementName("condition"); - and.saveSettings(configuration); + and.saveSettings(configuration); - and = new AndCondition(conditionFactory); - and.restoreSettings(configuration); + and = new AndCondition(conditionFactory); + and.restoreSettings(configuration); - assertThat("Sub conditions should not be null.", - and.getSubConditions(), is(notNullValue())); - assertThat("Sub condition count should be 2.", and.getSubConditions() - .size(), is(2)); - assertThat("'true && true' should be true.", and.matches(context), - is(true)); + assertThat("Sub conditions should not be null.", + and.getSubConditions(), is(notNullValue())); + assertThat("Sub condition count should be 2.", and.getSubConditions() + .size(), is(2)); + assertThat("'true && true' should be true.", and.matches(context), + is(true)); - System.out.println("Saved configuration : "); + System.out.println("Saved configuration : "); - configuration.save(System.out); - } + configuration.save(System.out); + } } diff --git a/pivot4j-core/src/test/java/org/pivot4j/ui/condition/ExpressionConditionTest.java b/pivot4j-core/src/test/java/org/pivot4j/ui/condition/ExpressionConditionTest.java index 2a001435..8d9d1a64 100644 --- a/pivot4j-core/src/test/java/org/pivot4j/ui/condition/ExpressionConditionTest.java +++ b/pivot4j-core/src/test/java/org/pivot4j/ui/condition/ExpressionConditionTest.java @@ -24,121 +24,121 @@ public class ExpressionConditionTest extends AbstractConditionTest { - @Test(expected = IllegalStateException.class) - public void testEmptyCondition() { - RenderContext context = createDummyRenderContext(); - - ExpressionCondition expression = new ExpressionCondition( - conditionFactory); - expression.matches(context); - } + @Test(expected = IllegalStateException.class) + public void testEmptyCondition() { + RenderContext context = createDummyRenderContext(); + + ExpressionCondition expression = new ExpressionCondition( + conditionFactory); + expression.matches(context); + } - @Test - public void testSimpleExpression() { - TableRenderContext context = createDummyRenderContext(); + @Test + public void testSimpleExpression() { + TableRenderContext context = createDummyRenderContext(); - ExpressionCondition expression = new ExpressionCondition( - conditionFactory); + ExpressionCondition expression = new ExpressionCondition( + conditionFactory); - expression.setExpression("true"); - assertThat("Expression '" + expression.getExpression() - + "' should be true.", expression.matches(context), is(true)); + expression.setExpression("true"); + assertThat("Expression '" + expression.getExpression() + + "' should be true.", expression.matches(context), is(true)); - expression.setExpression(" True "); - assertThat("Expression '" + expression.getExpression() - + "' should be true.", expression.matches(context), is(true)); + expression.setExpression(" True "); + assertThat("Expression '" + expression.getExpression() + + "' should be true.", expression.matches(context), is(true)); - expression.setExpression("abctrue"); - assertThat("Expression '" + expression.getExpression() - + "' should be false.", expression.matches(context), is(false)); + expression.setExpression("abctrue"); + assertThat("Expression '" + expression.getExpression() + + "' should be false.", expression.matches(context), is(false)); - context.setColIndex(2); - } + context.setColIndex(2); + } - @Test - public void testConditionalExpression() { - TableRenderContext context = createDummyRenderContext(); - context.setColIndex(2); - context.setRowIndex(1); - context.setAxis(Axis.ROWS); + @Test + public void testConditionalExpression() { + TableRenderContext context = createDummyRenderContext(); + context.setColIndex(2); + context.setRowIndex(1); + context.setAxis(Axis.ROWS); - ExpressionCondition expression = new ExpressionCondition( - conditionFactory); + ExpressionCondition expression = new ExpressionCondition( + conditionFactory); - expression.setExpression("<#if columnIndex = 2>true"); - assertThat("Expression '" + expression.getExpression() - + "' should be true.", expression.matches(context), is(true)); + expression.setExpression("<#if columnIndex = 2>true"); + assertThat("Expression '" + expression.getExpression() + + "' should be true.", expression.matches(context), is(true)); - expression.setExpression("<#if columnIndex != 2>true"); - assertThat("Expression '" + expression.getExpression() - + "' should be false.", expression.matches(context), is(false)); + expression.setExpression("<#if columnIndex != 2>true"); + assertThat("Expression '" + expression.getExpression() + + "' should be false.", expression.matches(context), is(false)); - expression - .setExpression("<#if columnIndex = 2 && rowIndex = 1>true"); - assertThat("Expression '" + expression.getExpression() - + "' should be true.", expression.matches(context), is(true)); + expression + .setExpression("<#if columnIndex = 2 && rowIndex = 1>true"); + assertThat("Expression '" + expression.getExpression() + + "' should be true.", expression.matches(context), is(true)); - expression.setExpression("<#if axis = \"ROWS\">true"); - assertThat("Expression '" + expression.getExpression() - + "' should be true.", expression.matches(context), is(true)); + expression.setExpression("<#if axis = \"ROWS\">true"); + assertThat("Expression '" + expression.getExpression() + + "' should be true.", expression.matches(context), is(true)); - expression.setExpression("<#if axis = \"COLUMNS\">true"); - assertThat("Expression '" + expression.getExpression() - + "' should be false.", expression.matches(context), is(false)); - } + expression.setExpression("<#if axis = \"COLUMNS\">true"); + assertThat("Expression '" + expression.getExpression() + + "' should be false.", expression.matches(context), is(false)); + } - @Test - public void testStateManagement() { - TableRenderContext context = createDummyRenderContext(); - context.setColIndex(2); - context.setRowIndex(1); - context.setAxis(Axis.ROWS); + @Test + public void testStateManagement() { + TableRenderContext context = createDummyRenderContext(); + context.setColIndex(2); + context.setRowIndex(1); + context.setAxis(Axis.ROWS); - String expression = "<#if columnIndex = 2 && rowIndex = 1>true"; + String expression = "<#if columnIndex = 2 && rowIndex = 1>true"; - ExpressionCondition condition = new ExpressionCondition( - conditionFactory); - condition.setExpression(expression); + ExpressionCondition condition = new ExpressionCondition( + conditionFactory); + condition.setExpression(expression); - Serializable state = condition.saveState(); + Serializable state = condition.saveState(); - condition = new ExpressionCondition(conditionFactory); - condition.restoreState(state); + condition = new ExpressionCondition(conditionFactory); + condition.restoreState(state); - assertThat("Expression has been changed.", condition.getExpression(), - is(equalTo(expression))); - assertThat("Expression '" + expression + "' should be true.", - condition.matches(context), is(true)); - } + assertThat("Expression has been changed.", condition.getExpression(), + is(equalTo(expression))); + assertThat("Expression '" + expression + "' should be true.", + condition.matches(context), is(true)); + } - @Test - public void testSettingsManagement() throws ConfigurationException { - TableRenderContext context = createDummyRenderContext(); - context.setColIndex(2); - context.setRowIndex(1); - context.setAxis(Axis.ROWS); + @Test + public void testSettingsManagement() throws ConfigurationException { + TableRenderContext context = createDummyRenderContext(); + context.setColIndex(2); + context.setRowIndex(1); + context.setAxis(Axis.ROWS); - String expression = "<#if columnIndex = 2 && rowIndex = 1>true"; + String expression = "<#if columnIndex = 2 && rowIndex = 1>true"; - ExpressionCondition condition = new ExpressionCondition( - conditionFactory); - condition.setExpression(expression); + ExpressionCondition condition = new ExpressionCondition( + conditionFactory); + condition.setExpression(expression); - XMLConfiguration configuration = new XMLConfiguration(); - configuration.setRootElementName("condition"); + XMLConfiguration configuration = new XMLConfiguration(); + configuration.setRootElementName("condition"); - condition.saveSettings(configuration); + condition.saveSettings(configuration); - condition = new ExpressionCondition(conditionFactory); - condition.restoreSettings(configuration); + condition = new ExpressionCondition(conditionFactory); + condition.restoreSettings(configuration); - assertThat("Expression has been changed.", condition.getExpression(), - is(equalTo(expression))); - assertThat("Expression '" + expression + "' should be true.", - condition.matches(context), is(true)); + assertThat("Expression has been changed.", condition.getExpression(), + is(equalTo(expression))); + assertThat("Expression '" + expression + "' should be true.", + condition.matches(context), is(true)); - System.out.println("Saved configuration : "); + System.out.println("Saved configuration : "); - configuration.save(System.out); - } + configuration.save(System.out); + } } diff --git a/pivot4j-core/src/test/java/org/pivot4j/ui/condition/NotConditionTest.java b/pivot4j-core/src/test/java/org/pivot4j/ui/condition/NotConditionTest.java index 554ad692..3d552271 100644 --- a/pivot4j-core/src/test/java/org/pivot4j/ui/condition/NotConditionTest.java +++ b/pivot4j-core/src/test/java/org/pivot4j/ui/condition/NotConditionTest.java @@ -22,65 +22,65 @@ public class NotConditionTest extends AbstractConditionTest { - @Test(expected = IllegalStateException.class) - public void testEmptyCondition() { - RenderContext context = createDummyRenderContext(); + @Test(expected = IllegalStateException.class) + public void testEmptyCondition() { + RenderContext context = createDummyRenderContext(); - NotCondition not = new NotCondition(conditionFactory); - not.matches(context); - } + NotCondition not = new NotCondition(conditionFactory); + not.matches(context); + } - @Test - public void testCondition() { - RenderContext context = createDummyRenderContext(); + @Test + public void testCondition() { + RenderContext context = createDummyRenderContext(); - NotCondition not = new NotCondition(conditionFactory); + NotCondition not = new NotCondition(conditionFactory); - not.setSubCondition(TestCondition.FALSE); - assertThat("'!false' should be true.", not.matches(context), is(true)); + not.setSubCondition(TestCondition.FALSE); + assertThat("'!false' should be true.", not.matches(context), is(true)); - not.setSubCondition(TestCondition.TRUE); - assertThat("'!true' should be false.", not.matches(context), is(false)); - } + not.setSubCondition(TestCondition.TRUE); + assertThat("'!true' should be false.", not.matches(context), is(false)); + } - @Test - public void testStateManagement() { - RenderContext context = createDummyRenderContext(); + @Test + public void testStateManagement() { + RenderContext context = createDummyRenderContext(); - NotCondition not = new NotCondition(conditionFactory); - not.setSubCondition(TestCondition.TRUE); + NotCondition not = new NotCondition(conditionFactory); + not.setSubCondition(TestCondition.TRUE); - Serializable state = not.saveState(); + Serializable state = not.saveState(); - not = new NotCondition(conditionFactory); - not.restoreState(state); + not = new NotCondition(conditionFactory); + not.restoreState(state); - assertThat("Sub condition should not be null.", not.getSubCondition(), - is(notNullValue())); - assertThat("'!true' should be false.", not.matches(context), is(false)); - } + assertThat("Sub condition should not be null.", not.getSubCondition(), + is(notNullValue())); + assertThat("'!true' should be false.", not.matches(context), is(false)); + } - @Test - public void testSettingsManagement() throws ConfigurationException { - RenderContext context = createDummyRenderContext(); + @Test + public void testSettingsManagement() throws ConfigurationException { + RenderContext context = createDummyRenderContext(); - NotCondition not = new NotCondition(conditionFactory); - not.setSubCondition(TestCondition.FALSE); + NotCondition not = new NotCondition(conditionFactory); + not.setSubCondition(TestCondition.FALSE); - XMLConfiguration configuration = new XMLConfiguration(); - configuration.setRootElementName("condition"); + XMLConfiguration configuration = new XMLConfiguration(); + configuration.setRootElementName("condition"); - not.saveSettings(configuration); + not.saveSettings(configuration); - not = new NotCondition(conditionFactory); - not.restoreSettings(configuration); + not = new NotCondition(conditionFactory); + not.restoreSettings(configuration); - assertThat("Sub condition should not be null.", not.getSubCondition(), - is(notNullValue())); - assertThat("'!false' should be true.", not.matches(context), is(true)); + assertThat("Sub condition should not be null.", not.getSubCondition(), + is(notNullValue())); + assertThat("'!false' should be true.", not.matches(context), is(true)); - System.out.println("Saved configuration : "); + System.out.println("Saved configuration : "); - configuration.save(System.out); - } + configuration.save(System.out); + } } diff --git a/pivot4j-core/src/test/java/org/pivot4j/ui/condition/OrConditionTest.java b/pivot4j-core/src/test/java/org/pivot4j/ui/condition/OrConditionTest.java index 1ae71739..f7f9ac55 100644 --- a/pivot4j-core/src/test/java/org/pivot4j/ui/condition/OrConditionTest.java +++ b/pivot4j-core/src/test/java/org/pivot4j/ui/condition/OrConditionTest.java @@ -23,85 +23,85 @@ public class OrConditionTest extends AbstractConditionTest { - @Test(expected = IllegalStateException.class) - public void testEmptyCondition() { - RenderContext context = createDummyRenderContext(); + @Test(expected = IllegalStateException.class) + public void testEmptyCondition() { + RenderContext context = createDummyRenderContext(); - OrCondition or = new OrCondition(conditionFactory); - or.matches(context); - } + OrCondition or = new OrCondition(conditionFactory); + or.matches(context); + } - @Test - public void testCondition() { - RenderContext context = createDummyRenderContext(); + @Test + public void testCondition() { + RenderContext context = createDummyRenderContext(); - OrCondition or = new OrCondition(conditionFactory); + OrCondition or = new OrCondition(conditionFactory); - or.setSubConditions(Arrays.asList(TestCondition.TRUE, - TestCondition.TRUE)); - assertThat("'true || true' should be true.", or.matches(context), - is(true)); + or.setSubConditions(Arrays.asList(TestCondition.TRUE, + TestCondition.TRUE)); + assertThat("'true || true' should be true.", or.matches(context), + is(true)); - or.setSubConditions(Arrays.asList(TestCondition.TRUE, - TestCondition.FALSE)); - assertThat("'true || false' should be true.", or.matches(context), - is(true)); + or.setSubConditions(Arrays.asList(TestCondition.TRUE, + TestCondition.FALSE)); + assertThat("'true || false' should be true.", or.matches(context), + is(true)); - or.setSubConditions(Arrays.asList(TestCondition.TRUE)); - assertThat("'true' should be true.", or.matches(context), is(true)); + or.setSubConditions(Arrays.asList(TestCondition.TRUE)); + assertThat("'true' should be true.", or.matches(context), is(true)); - or.setSubConditions(Arrays.asList(TestCondition.FALSE, - TestCondition.FALSE, TestCondition.TRUE)); - assertThat("'false || false || true' should be true.", - or.matches(context), is(true)); - } + or.setSubConditions(Arrays.asList(TestCondition.FALSE, + TestCondition.FALSE, TestCondition.TRUE)); + assertThat("'false || false || true' should be true.", + or.matches(context), is(true)); + } - @Test - public void testStateManagement() { - RenderContext context = createDummyRenderContext(); + @Test + public void testStateManagement() { + RenderContext context = createDummyRenderContext(); - OrCondition or = new OrCondition(conditionFactory); - or.setSubConditions(Arrays.asList(TestCondition.TRUE, - TestCondition.FALSE)); + OrCondition or = new OrCondition(conditionFactory); + or.setSubConditions(Arrays.asList(TestCondition.TRUE, + TestCondition.FALSE)); - Serializable state = or.saveState(); + Serializable state = or.saveState(); - or = new OrCondition(conditionFactory); - or.restoreState(state); + or = new OrCondition(conditionFactory); + or.restoreState(state); - assertThat("Sub conditions should not be null.", or.getSubConditions(), - is(notNullValue())); - assertThat("Sub condition count should be 2.", or.getSubConditions() - .size(), is(2)); - assertThat("'true || false' should be true.", or.matches(context), - is(true)); - } + assertThat("Sub conditions should not be null.", or.getSubConditions(), + is(notNullValue())); + assertThat("Sub condition count should be 2.", or.getSubConditions() + .size(), is(2)); + assertThat("'true || false' should be true.", or.matches(context), + is(true)); + } - @Test - public void testSettingsManagement() throws ConfigurationException { - RenderContext context = createDummyRenderContext(); + @Test + public void testSettingsManagement() throws ConfigurationException { + RenderContext context = createDummyRenderContext(); - OrCondition or = new OrCondition(conditionFactory); - or.setSubConditions(Arrays.asList(TestCondition.TRUE, - TestCondition.FALSE)); + OrCondition or = new OrCondition(conditionFactory); + or.setSubConditions(Arrays.asList(TestCondition.TRUE, + TestCondition.FALSE)); - XMLConfiguration configuration = new XMLConfiguration(); - configuration.setRootElementName("condition"); + XMLConfiguration configuration = new XMLConfiguration(); + configuration.setRootElementName("condition"); - or.saveSettings(configuration); + or.saveSettings(configuration); - or = new OrCondition(conditionFactory); - or.restoreSettings(configuration); + or = new OrCondition(conditionFactory); + or.restoreSettings(configuration); - assertThat("Sub conditions should not be null.", or.getSubConditions(), - is(notNullValue())); - assertThat("Sub condition count should be 2.", or.getSubConditions() - .size(), is(2)); - assertThat("'true || false' should be true.", or.matches(context), - is(true)); + assertThat("Sub conditions should not be null.", or.getSubConditions(), + is(notNullValue())); + assertThat("Sub condition count should be 2.", or.getSubConditions() + .size(), is(2)); + assertThat("'true || false' should be true.", or.matches(context), + is(true)); - System.out.println("Saved configuration : "); + System.out.println("Saved configuration : "); - configuration.save(System.out); - } + configuration.save(System.out); + } } diff --git a/pivot4j-core/src/test/java/org/pivot4j/ui/fop/FopExporterIT.java b/pivot4j-core/src/test/java/org/pivot4j/ui/fop/FopExporterIT.java index 6c698855..6c8655f7 100644 --- a/pivot4j-core/src/test/java/org/pivot4j/ui/fop/FopExporterIT.java +++ b/pivot4j-core/src/test/java/org/pivot4j/ui/fop/FopExporterIT.java @@ -24,50 +24,50 @@ public class FopExporterIT extends AbstractIntegrationTestCase { - private String testQuery = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "Hierarchize(Union(Union(CrossJoin({[Time].[1997]}, {[Promotion Media].[All Media]}), " - + "CrossJoin({[Time].[1997]}, [Promotion Media].[All Media].Children)), " - + "{CrossJoin({[Time].[1998]}, [Promotion Media].[All Media].Children)})) ON ROWS FROM [Sales]"; + private String testQuery = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "Hierarchize(Union(Union(CrossJoin({[Time].[1997]}, {[Promotion Media].[All Media]}), " + + "CrossJoin({[Time].[1997]}, [Promotion Media].[All Media].Children)), " + + "{CrossJoin({[Time].[1998]}, [Promotion Media].[All Media].Children)})) ON ROWS FROM [Sales]"; - private boolean deleteTestFile = true; + private boolean deleteTestFile = true; - /** - * @see org.pivot4j.AbstractIntegrationTestCase#setUp() - */ - @Override - public void setUp() throws Exception { - super.setUp(); + /** + * @see org.pivot4j.AbstractIntegrationTestCase#setUp() + */ + @Override + public void setUp() throws Exception { + super.setUp(); - PivotModel model = getPivotModel(); - model.setMdx(testQuery); - model.initialize(); - } + PivotModel model = getPivotModel(); + model.setMdx(testQuery); + model.initialize(); + } - @Test - public void testExportPdf() throws IOException { - OutputStream out = null; + @Test + public void testExportPdf() throws IOException { + OutputStream out = null; - File file = File.createTempFile("pivot4j-", ".pdf"); + File file = File.createTempFile("pivot4j-", ".pdf"); - if (deleteTestFile) { - file.deleteOnExit(); - } + if (deleteTestFile) { + file.deleteOnExit(); + } - try { - out = new FileOutputStream(file); + try { + out = new FileOutputStream(file); - TableRenderer renderer = new TableRenderer(); - renderer.setShowParentMembers(true); - renderer.setShowDimensionTitle(true); - renderer.setHideSpans(false); + TableRenderer renderer = new TableRenderer(); + renderer.setShowParentMembers(true); + renderer.setShowDimensionTitle(true); + renderer.setHideSpans(false); - FopExporter exporter = new FopExporter(out); - exporter.setOrientation(OrientationRequested.LANDSCAPE); + FopExporter exporter = new FopExporter(out); + exporter.setOrientation(OrientationRequested.LANDSCAPE); - renderer.render(getPivotModel(), exporter); - } finally { - out.flush(); - IOUtils.closeQuietly(out); - } - } + renderer.render(getPivotModel(), exporter); + } finally { + out.flush(); + IOUtils.closeQuietly(out); + } + } } diff --git a/pivot4j-core/src/test/java/org/pivot4j/ui/html/HtmlRendererIT.java b/pivot4j-core/src/test/java/org/pivot4j/ui/html/HtmlRendererIT.java index 1bb4c303..1f0e03d0 100644 --- a/pivot4j-core/src/test/java/org/pivot4j/ui/html/HtmlRendererIT.java +++ b/pivot4j-core/src/test/java/org/pivot4j/ui/html/HtmlRendererIT.java @@ -24,127 +24,127 @@ public class HtmlRendererIT extends AbstractIntegrationTestCase { - /** - * @param name - * @throws IOException - */ - protected void runTestCase(String name) throws IOException { - runTestCase(name, true, true, true); - runTestCase(name, true, true, false); - runTestCase(name, true, false, false); - runTestCase(name, true, false, true); - runTestCase(name, false, true, true); - runTestCase(name, false, true, false); - runTestCase(name, false, false, true); - runTestCase(name, false, false, false); - } - - /** - * @param name - * @param hideSpans - * @param showDimensionTitle - * @param showParentMembers - * @throws IOException - */ - protected void runTestCase(String name, boolean hideSpans, - boolean showDimensionTitle, boolean showParentMembers) - throws IOException { - String mdx = readTestResource(name + "-mdx.txt"); - - PivotModel model = getPivotModel(); - model.setMdx(mdx); - model.initialize(); - - StringBuilder sb = new StringBuilder(); - sb.append(name); - sb.append("-"); - sb.append(Boolean.toString(hideSpans)); - sb.append("-"); - sb.append(Boolean.toString(showDimensionTitle)); - sb.append("-"); - sb.append(Boolean.toString(showParentMembers)); - sb.append("-result.html"); - - String fileName = sb.toString(); - - StringWriter writer = new StringWriter(); - - TableRenderer renderer = new TableRenderer(); - - renderer.setHideSpans(hideSpans); - renderer.setShowDimensionTitle(showDimensionTitle); - renderer.setShowParentMembers(showParentMembers); - - if (name.contains("properties")) { - renderer.setPropertyCollector(new NonInternalPropertyCollector()); - } - - HtmlRenderCallback callback = new HtmlRenderCallback(writer); - callback.setBorder(1); - - renderer.render(model, callback); - - writer.flush(); - writer.close(); - - String result = writer.toString().trim() - .replace(System.getProperty("line.separator"), "\n"); - - String expected = readTestResource(fileName); - - String message = String - .format("Unexpected result : %s, hideSpans=%s, showDimensionTitle=%s, showParentMembers=%s", - name, hideSpans, showDimensionTitle, showParentMembers); - assertThat(message, result, is(equalTo(expected))); - } - - @Test - public void testBasicGrid() throws IOException { - runTestCase("basic"); - } - - @Test - public void testComplexColumns() throws IOException { - runTestCase("complex-columns"); - } - - @Test - public void testMoreComplexColumns() throws IOException { - runTestCase("more-complex-columns"); - } - - @Test - public void testInsaneRows() throws IOException { - runTestCase("insane-rows"); - } - - @Test - public void testSkippingLevel() throws IOException { - runTestCase("skipping-level"); - } - - @Test - public void testMemberProperties() throws IOException { - runTestCase("member-properties"); - } - - @Test - public void testComplexMemberProperties() throws IOException { - runTestCase("complex-member-properties"); - } - - @Test - public void testParentChildHierarchy() throws IOException { - runTestCase("parent-child"); - } - - @Test - public void testSingleDimensionCrossJoin() throws IOException { - runTestCase("single-dim-crossjoin"); - } - - @Test - public void testRaggedHierarchy() throws IOException { - runTestCase("ragged"); - } + /** + * @param name + * @throws IOException + */ + protected void runTestCase(String name) throws IOException { + runTestCase(name, true, true, true); + runTestCase(name, true, true, false); + runTestCase(name, true, false, false); + runTestCase(name, true, false, true); + runTestCase(name, false, true, true); + runTestCase(name, false, true, false); + runTestCase(name, false, false, true); + runTestCase(name, false, false, false); + } + + /** + * @param name + * @param hideSpans + * @param showDimensionTitle + * @param showParentMembers + * @throws IOException + */ + protected void runTestCase(String name, boolean hideSpans, + boolean showDimensionTitle, boolean showParentMembers) + throws IOException { + String mdx = readTestResource(name + "-mdx.txt"); + + PivotModel model = getPivotModel(); + model.setMdx(mdx); + model.initialize(); + + StringBuilder sb = new StringBuilder(); + sb.append(name); + sb.append("-"); + sb.append(Boolean.toString(hideSpans)); + sb.append("-"); + sb.append(Boolean.toString(showDimensionTitle)); + sb.append("-"); + sb.append(Boolean.toString(showParentMembers)); + sb.append("-result.html"); + + String fileName = sb.toString(); + + StringWriter writer = new StringWriter(); + + TableRenderer renderer = new TableRenderer(); + + renderer.setHideSpans(hideSpans); + renderer.setShowDimensionTitle(showDimensionTitle); + renderer.setShowParentMembers(showParentMembers); + + if (name.contains("properties")) { + renderer.setPropertyCollector(new NonInternalPropertyCollector()); + } + + HtmlRenderCallback callback = new HtmlRenderCallback(writer); + callback.setBorder(1); + + renderer.render(model, callback); + + writer.flush(); + writer.close(); + + String result = writer.toString().trim() + .replace(System.getProperty("line.separator"), "\n"); + + String expected = readTestResource(fileName); + + String message = String + .format("Unexpected result : %s, hideSpans=%s, showDimensionTitle=%s, showParentMembers=%s", + name, hideSpans, showDimensionTitle, showParentMembers); + assertThat(message, result, is(equalTo(expected))); + } + + @Test + public void testBasicGrid() throws IOException { + runTestCase("basic"); + } + + @Test + public void testComplexColumns() throws IOException { + runTestCase("complex-columns"); + } + + @Test + public void testMoreComplexColumns() throws IOException { + runTestCase("more-complex-columns"); + } + + @Test + public void testInsaneRows() throws IOException { + runTestCase("insane-rows"); + } + + @Test + public void testSkippingLevel() throws IOException { + runTestCase("skipping-level"); + } + + @Test + public void testMemberProperties() throws IOException { + runTestCase("member-properties"); + } + + @Test + public void testComplexMemberProperties() throws IOException { + runTestCase("complex-member-properties"); + } + + @Test + public void testParentChildHierarchy() throws IOException { + runTestCase("parent-child"); + } + + @Test + public void testSingleDimensionCrossJoin() throws IOException { + runTestCase("single-dim-crossjoin"); + } + + @Test + public void testRaggedHierarchy() throws IOException { + runTestCase("ragged"); + } } diff --git a/pivot4j-core/src/test/java/org/pivot4j/ui/poi/ExcelExporterIT.java b/pivot4j-core/src/test/java/org/pivot4j/ui/poi/ExcelExporterIT.java index 6a02eff7..ded6e5d3 100644 --- a/pivot4j-core/src/test/java/org/pivot4j/ui/poi/ExcelExporterIT.java +++ b/pivot4j-core/src/test/java/org/pivot4j/ui/poi/ExcelExporterIT.java @@ -32,102 +32,102 @@ public class ExcelExporterIT extends AbstractIntegrationTestCase { - private String testQuery = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " - + "Hierarchize(Union(Union(CrossJoin({[Time].[1997]}, {[Promotion Media].[All Media]}), " - + "CrossJoin({[Time].[1997]}, [Promotion Media].[All Media].Children)), " - + "{([Time].[1998], [Promotion Media].[All Media])})) ON ROWS FROM [Sales]"; - - private boolean deleteTestFile = true; - - /** - * @see org.pivot4j.AbstractIntegrationTestCase#setUp() - */ - @Override - public void setUp() throws Exception { - super.setUp(); - - PivotModel model = getPivotModel(); - model.setMdx(testQuery); - model.initialize(); - } - - @Test - public void testExportHSSF() throws IOException, InvalidFormatException { - testExport(Format.HSSF, true, true, false, 17, 6); - testExport(Format.HSSF, false, true, false, 17, 3); - testExport(Format.HSSF, true, false, false, 16, 5); - testExport(Format.HSSF, true, false, true, 16, 3); - } - - @Test - public void testExportXSSF() throws IOException, InvalidFormatException { - testExport(Format.XSSF, true, true, false, 17, 6); - testExport(Format.XSSF, false, true, false, 17, 3); - testExport(Format.XSSF, true, false, false, 16, 5); - testExport(Format.XSSF, true, false, true, 16, 3); - } - - @Test - public void testExportSXSSF() throws IOException, InvalidFormatException { - testExport(Format.SXSSF, true, true, false, 17, 6); - testExport(Format.SXSSF, false, true, false, 17, 3); - testExport(Format.SXSSF, true, false, false, 16, 5); - testExport(Format.SXSSF, true, false, true, 16, 3); - } - - /** - * @param format - * @param showParentMember - * @param showDimensionTitle - * @param hideSpans - * @param rows - * @param mergedRegions - * @throws IOException - * @throws InvalidFormatException - */ - protected void testExport(Format format, boolean showParentMember, - boolean showDimensionTitle, boolean hideSpans, int rows, - int mergedRegions) throws IOException, InvalidFormatException { - OutputStream out = null; - - File file = File - .createTempFile("pivot4j-", "." + format.getExtension()); - - if (deleteTestFile) { - file.deleteOnExit(); - } - - try { - out = new FileOutputStream(file); - - TableRenderer renderer = new TableRenderer(); - - renderer.setShowParentMembers(showParentMember); - renderer.setShowDimensionTitle(showDimensionTitle); - renderer.setHideSpans(hideSpans); - - ExcelExporter exporter = new ExcelExporter(out); - exporter.setFormat(format); - - renderer.render(getPivotModel(), exporter); - } finally { - out.flush(); - IOUtils.closeQuietly(out); - } - - Workbook workbook = WorkbookFactory.create(file); - - assertThat("Workbook cannot be null.", workbook, is(notNullValue())); - - Sheet sheet = workbook.getSheetAt(0); - assertThat("Worksheet cannot be null.", sheet, is(notNullValue())); - - assertThat("Invalid worksheet name.", sheet.getSheetName(), - is(equalTo("Sales"))); - - assertThat("Wrong number of rows.", sheet.getLastRowNum(), - is(equalTo(rows))); - assertThat("Wrong number of merged regions.", - sheet.getNumMergedRegions(), is(equalTo(mergedRegions))); - } + private String testQuery = "SELECT {[Measures].[Unit Sales], [Measures].[Store Cost], [Measures].[Store Sales]} ON COLUMNS, " + + "Hierarchize(Union(Union(CrossJoin({[Time].[1997]}, {[Promotion Media].[All Media]}), " + + "CrossJoin({[Time].[1997]}, [Promotion Media].[All Media].Children)), " + + "{([Time].[1998], [Promotion Media].[All Media])})) ON ROWS FROM [Sales]"; + + private boolean deleteTestFile = true; + + /** + * @see org.pivot4j.AbstractIntegrationTestCase#setUp() + */ + @Override + public void setUp() throws Exception { + super.setUp(); + + PivotModel model = getPivotModel(); + model.setMdx(testQuery); + model.initialize(); + } + + @Test + public void testExportHSSF() throws IOException, InvalidFormatException { + testExport(Format.HSSF, true, true, false, 17, 6); + testExport(Format.HSSF, false, true, false, 17, 3); + testExport(Format.HSSF, true, false, false, 16, 5); + testExport(Format.HSSF, true, false, true, 16, 3); + } + + @Test + public void testExportXSSF() throws IOException, InvalidFormatException { + testExport(Format.XSSF, true, true, false, 17, 6); + testExport(Format.XSSF, false, true, false, 17, 3); + testExport(Format.XSSF, true, false, false, 16, 5); + testExport(Format.XSSF, true, false, true, 16, 3); + } + + @Test + public void testExportSXSSF() throws IOException, InvalidFormatException { + testExport(Format.SXSSF, true, true, false, 17, 6); + testExport(Format.SXSSF, false, true, false, 17, 3); + testExport(Format.SXSSF, true, false, false, 16, 5); + testExport(Format.SXSSF, true, false, true, 16, 3); + } + + /** + * @param format + * @param showParentMember + * @param showDimensionTitle + * @param hideSpans + * @param rows + * @param mergedRegions + * @throws IOException + * @throws InvalidFormatException + */ + protected void testExport(Format format, boolean showParentMember, + boolean showDimensionTitle, boolean hideSpans, int rows, + int mergedRegions) throws IOException, InvalidFormatException { + OutputStream out = null; + + File file = File + .createTempFile("pivot4j-", "." + format.getExtension()); + + if (deleteTestFile) { + file.deleteOnExit(); + } + + try { + out = new FileOutputStream(file); + + TableRenderer renderer = new TableRenderer(); + + renderer.setShowParentMembers(showParentMember); + renderer.setShowDimensionTitle(showDimensionTitle); + renderer.setHideSpans(hideSpans); + + ExcelExporter exporter = new ExcelExporter(out); + exporter.setFormat(format); + + renderer.render(getPivotModel(), exporter); + } finally { + out.flush(); + IOUtils.closeQuietly(out); + } + + Workbook workbook = WorkbookFactory.create(file); + + assertThat("Workbook cannot be null.", workbook, is(notNullValue())); + + Sheet sheet = workbook.getSheetAt(0); + assertThat("Worksheet cannot be null.", sheet, is(notNullValue())); + + assertThat("Invalid worksheet name.", sheet.getSheetName(), + is(equalTo("Sales"))); + + assertThat("Wrong number of rows.", sheet.getLastRowNum(), + is(equalTo(rows))); + assertThat("Wrong number of merged regions.", + sheet.getNumMergedRegions(), is(equalTo(mergedRegions))); + } } diff --git a/pivot4j-core/src/test/java/org/pivot4j/ui/property/ConditionalPropertyTest.java b/pivot4j-core/src/test/java/org/pivot4j/ui/property/ConditionalPropertyTest.java index 80d3d067..6ede93f4 100644 --- a/pivot4j-core/src/test/java/org/pivot4j/ui/property/ConditionalPropertyTest.java +++ b/pivot4j-core/src/test/java/org/pivot4j/ui/property/ConditionalPropertyTest.java @@ -34,131 +34,131 @@ public class ConditionalPropertyTest extends AbstractMockRenderTestCase { - private ConditionalRenderProperty property; + private ConditionalRenderProperty property; - @Before - public void setUp() throws Exception { - ConditionFactory factory = new DefaultConditionFactory(); + @Before + public void setUp() throws Exception { + ConditionFactory factory = new DefaultConditionFactory(); - this.property = new ConditionalRenderProperty("bgColor", factory); + this.property = new ConditionalRenderProperty("bgColor", factory); - ExpressionCondition expression1 = new ExpressionCondition(factory, - "<#if rowIndex = 3>true"); - ExpressionCondition expression2 = new ExpressionCondition(factory, - "<#if rowIndex = 4>true"); + ExpressionCondition expression1 = new ExpressionCondition(factory, + "<#if rowIndex = 3>true"); + ExpressionCondition expression2 = new ExpressionCondition(factory, + "<#if rowIndex = 4>true"); - OrCondition or = new OrCondition(factory, expression1, expression2); + OrCondition or = new OrCondition(factory, expression1, expression2); - List values = new LinkedList(); + List values = new LinkedList(); - values.add(new ConditionalValue(new ExpressionCondition(factory, - "<#if columnIndex = 1>true"), "red")); - values.add(new ConditionalValue(or, "blue")); + values.add(new ConditionalValue(new ExpressionCondition(factory, + "<#if columnIndex = 1>true"), "red")); + values.add(new ConditionalValue(or, "blue")); - property.setDefaultValue("black"); - property.setValues(values); - } + property.setDefaultValue("black"); + property.setValues(values); + } - @After - public void tearDown() throws Exception { - this.property = null; - } + @After + public void tearDown() throws Exception { + this.property = null; + } - @Test - public void testNullValue() { - RenderContext context = createDummyRenderContext(); + @Test + public void testNullValue() { + RenderContext context = createDummyRenderContext(); - property.setValues(null); + property.setValues(null); - String result = property.getValue(context); + String result = property.getValue(context); - assertThat("Wrong property value.", result, is(nullValue())); - } + assertThat("Wrong property value.", result, is(nullValue())); + } - @Test - public void testDefaultValue() { - TableRenderContext context = createDummyRenderContext(); - context.setColIndex(2); - context.setRowIndex(1); + @Test + public void testDefaultValue() { + TableRenderContext context = createDummyRenderContext(); + context.setColIndex(2); + context.setRowIndex(1); - String result = property.getValue(context); + String result = property.getValue(context); - assertThat("Wrong property value.", result, is(equalTo("black"))); - } + assertThat("Wrong property value.", result, is(equalTo("black"))); + } - @Test - public void testSimpleValue() { - TableRenderContext context = createDummyRenderContext(); - context.setColIndex(1); - context.setRowIndex(2); + @Test + public void testSimpleValue() { + TableRenderContext context = createDummyRenderContext(); + context.setColIndex(1); + context.setRowIndex(2); - String result = property.getValue(context); + String result = property.getValue(context); - assertThat("Wrong property value.", result, is(equalTo("red"))); - } + assertThat("Wrong property value.", result, is(equalTo("red"))); + } - @Test - public void testConditionValue() { - TableRenderContext context = createDummyRenderContext(); - context.setColIndex(2); - context.setRowIndex(4); + @Test + public void testConditionValue() { + TableRenderContext context = createDummyRenderContext(); + context.setColIndex(2); + context.setRowIndex(4); - String result = property.getValue(context); + String result = property.getValue(context); - assertThat("Wrong property value.", result, is(equalTo("blue"))); - } + assertThat("Wrong property value.", result, is(equalTo("blue"))); + } - @Test - public void testStateManagement() { - Serializable state = property.saveState(); + @Test + public void testStateManagement() { + Serializable state = property.saveState(); - ConditionalRenderProperty property2 = new ConditionalRenderProperty( - new DefaultConditionFactory()); + ConditionalRenderProperty property2 = new ConditionalRenderProperty( + new DefaultConditionFactory()); - property2.restoreState(state); + property2.restoreState(state); - assertThat("RenderProperty name has been changed.", - property2.getName(), is(equalTo(property.getName()))); - assertThat("Default value has been changed.", - property2.getDefaultValue(), - is(equalTo(property.getDefaultValue()))); + assertThat("RenderProperty name has been changed.", + property2.getName(), is(equalTo(property.getName()))); + assertThat("Default value has been changed.", + property2.getDefaultValue(), + is(equalTo(property.getDefaultValue()))); - TableRenderContext context = createDummyRenderContext(); - context.setColIndex(2); - context.setRowIndex(4); + TableRenderContext context = createDummyRenderContext(); + context.setColIndex(2); + context.setRowIndex(4); - String result = property2.getValue(context); + String result = property2.getValue(context); - assertThat("Wrong property value.", result, is(equalTo("blue"))); - } + assertThat("Wrong property value.", result, is(equalTo("blue"))); + } - @Test - public void testSettingsManagement() throws ConfigurationException { - XMLConfiguration configuration = new XMLConfiguration(); - configuration.setRootElementName("property"); + @Test + public void testSettingsManagement() throws ConfigurationException { + XMLConfiguration configuration = new XMLConfiguration(); + configuration.setRootElementName("property"); - property.saveSettings(configuration); - System.out.println("Saved configuration : "); - configuration.save(System.out); - ConditionalRenderProperty property2 = new ConditionalRenderProperty( - new DefaultConditionFactory()); - property2.restoreSettings(configuration); + property.saveSettings(configuration); + System.out.println("Saved configuration : "); + configuration.save(System.out); + ConditionalRenderProperty property2 = new ConditionalRenderProperty( + new DefaultConditionFactory()); + property2.restoreSettings(configuration); - assertThat("RenderProperty name has been changed.", - property2.getName(), is(equalTo(property.getName()))); - assertThat("Default value has been changed.", - property2.getDefaultValue(), - is(equalTo(property.getDefaultValue()))); + assertThat("RenderProperty name has been changed.", + property2.getName(), is(equalTo(property.getName()))); + assertThat("Default value has been changed.", + property2.getDefaultValue(), + is(equalTo(property.getDefaultValue()))); - TableRenderContext context = createDummyRenderContext(); - context.setColIndex(2); - context.setRowIndex(4); + TableRenderContext context = createDummyRenderContext(); + context.setColIndex(2); + context.setRowIndex(4); - String result = property2.getValue(context); + String result = property2.getValue(context); - assertThat("Wrong property value.", result, is(equalTo("blue"))); + assertThat("Wrong property value.", result, is(equalTo("blue"))); - System.out.println("Saved configuration : "); - configuration.save(System.out); - } + System.out.println("Saved configuration : "); + configuration.save(System.out); + } } diff --git a/pivot4j-core/src/test/java/org/pivot4j/ui/property/SimplePropertyRenderingIT.java b/pivot4j-core/src/test/java/org/pivot4j/ui/property/SimplePropertyRenderingIT.java index dedf8f90..71bd7d22 100644 --- a/pivot4j-core/src/test/java/org/pivot4j/ui/property/SimplePropertyRenderingIT.java +++ b/pivot4j-core/src/test/java/org/pivot4j/ui/property/SimplePropertyRenderingIT.java @@ -35,195 +35,196 @@ public class SimplePropertyRenderingIT extends AbstractHtmlTableTestCase { - /** - * @see org.pivot4j.ui.AbstractHtmlTableTestCase#getQueryName() - */ - @Override - protected String getQueryName() { - return "simple"; - } + /** + * @see org.pivot4j.ui.AbstractHtmlTableTestCase#getQueryName() + */ + @Override + protected String getQueryName() { + return "simple"; + } - /** - * @see org.pivot4j.ui.AbstractHtmlTableTestCase#configureRenderer(org.pivot4j.ui.table.TableRenderer) - */ - @Override - protected void configureRenderer(TableRenderer renderer) { - super.configureRenderer(renderer); + /** + * @see + * org.pivot4j.ui.AbstractHtmlTableTestCase#configureRenderer(org.pivot4j.ui.table.TableRenderer) + */ + @Override + protected void configureRenderer(TableRenderer renderer) { + super.configureRenderer(renderer); - RenderPropertyList headerProperties = renderer.getRenderProperties() - .get(HEADER); - RenderPropertyList cellProperties = renderer.getRenderProperties().get( - CELL); + RenderPropertyList headerProperties = renderer.getRenderProperties() + .get(HEADER); + RenderPropertyList cellProperties = renderer.getRenderProperties().get( + CELL); - headerProperties.setRenderProperty(new SimpleRenderProperty("bgColor", - "<#if member?? && member.level.depth == 2>#990000")); - headerProperties.setRenderProperty(new SimpleRenderProperty( - "fontFamily", "serif")); - headerProperties.setRenderProperty(new SimpleRenderProperty( - "fontStyle", - "<#if member?? && member.caption == 'Drink'>italic")); - headerProperties - .setRenderProperty(new SimpleRenderProperty( - "link", - "<#if member?? && member.all>javascript: alert('Unique name : ${member.uniqueName}');")); + headerProperties.setRenderProperty(new SimpleRenderProperty("bgColor", + "<#if member?? && member.level.depth == 2>#990000")); + headerProperties.setRenderProperty(new SimpleRenderProperty( + "fontFamily", "serif")); + headerProperties.setRenderProperty(new SimpleRenderProperty( + "fontStyle", + "<#if member?? && member.caption == 'Drink'>italic")); + headerProperties + .setRenderProperty(new SimpleRenderProperty( + "link", + "<#if member?? && member.all>javascript: alert('Unique name : ${member.uniqueName}');")); - cellProperties.setRenderProperty(new SimpleRenderProperty("fgColor", - "<#if cell?? && cell.doubleValue < 15000>#ff0000")); - cellProperties.setRenderProperty(new SimpleRenderProperty("bgColor", - "<#if aggregator?? && cellType == 'VALUE'>#00aa00")); - cellProperties.setRenderProperty(new SimpleRenderProperty("fontStyle", - "<#if cell?? && cell.doubleValue < 15000>bold")); - cellProperties.setRenderProperty(new SimpleRenderProperty("label", - "<#if cell??>${'$'}${cell.formattedValue}")); - } + cellProperties.setRenderProperty(new SimpleRenderProperty("fgColor", + "<#if cell?? && cell.doubleValue < 15000>#ff0000")); + cellProperties.setRenderProperty(new SimpleRenderProperty("bgColor", + "<#if aggregator?? && cellType == 'VALUE'>#00aa00")); + cellProperties.setRenderProperty(new SimpleRenderProperty("fontStyle", + "<#if cell?? && cell.doubleValue < 15000>bold")); + cellProperties.setRenderProperty(new SimpleRenderProperty("label", + "<#if cell??>${'$'}${cell.formattedValue}")); + } - @Test - public void testColumnHeader() throws IOException { - HtmlTable table = getTable(); + @Test + public void testColumnHeader() throws IOException { + HtmlTable table = getTable(); - HtmlTableHeader header = table.getHeader(); + HtmlTableHeader header = table.getHeader(); - List rows = header.getRows(); + List rows = header.getRows(); - assertCell(rows, 0, 0, 1, 4, "Product"); + assertCell(rows, 0, 0, 1, 4, "Product"); - Map styles = getCellStyles(rows, 0, 0); + Map styles = getCellStyles(rows, 0, 0); - assertThat("Wrong number of style rules", styles.size(), is(equalTo(1))); - assertThat("The cell has a wrong font family style", - styles.get("font-family"), is(equalTo("serif"))); + assertThat("Wrong number of style rules", styles.size(), is(equalTo(1))); + assertThat("The cell has a wrong font family style", + styles.get("font-family"), is(equalTo("serif"))); - assertCell(rows, 0, 1, 1, 3, "Measures"); + assertCell(rows, 0, 1, 1, 3, "Measures"); - styles = getCellStyles(rows, 0, 1); + styles = getCellStyles(rows, 0, 1); - assertThat("Wrong number of style rules", styles.size(), is(equalTo(1))); - assertThat("The cell has a wrong font family style", - styles.get("font-family"), is(equalTo("serif"))); - } + assertThat("Wrong number of style rules", styles.size(), is(equalTo(1))); + assertThat("The cell has a wrong font family style", + styles.get("font-family"), is(equalTo("serif"))); + } - @Test - public void testRowHeaderAllProducts() throws IOException { - HtmlTable table = getTable(); + @Test + public void testRowHeaderAllProducts() throws IOException { + HtmlTable table = getTable(); - HtmlTableBody body = table.getBodies().get(0); + HtmlTableBody body = table.getBodies().get(0); - List rows = body.getRows(); + List rows = body.getRows(); - assertCell(rows, 1, 0, 22, 1, "All Products"); + assertCell(rows, 1, 0, 22, 1, "All Products"); - HtmlTableCell cell = rows.get(1).getCells().get(0); + HtmlTableCell cell = rows.get(1).getCells().get(0); - assertThat("Unable to find an tag", cell.getChildElementCount(), - is(equalTo(1))); + assertThat("Unable to find an tag", cell.getChildElementCount(), + is(equalTo(1))); - DomElement elem = cell.getChildElements().iterator().next(); + DomElement elem = cell.getChildElements().iterator().next(); - assertThat("Unable to find an tag", elem.getClass(), - typeCompatibleWith(HtmlAnchor.class)); + assertThat("Unable to find an tag", elem.getClass(), + typeCompatibleWith(HtmlAnchor.class)); - HtmlAnchor link = (HtmlAnchor) elem; + HtmlAnchor link = (HtmlAnchor) elem; - assertThat( - "The cell has an invalid link target", - link.getHrefAttribute(), - is(equalTo("javascript: alert('Unique name : [Product].[All Products]');"))); + assertThat( + "The cell has an invalid link target", + link.getHrefAttribute(), + is(equalTo("javascript: alert('Unique name : [Product].[All Products]');"))); - Map styles = getCellStyles(rows, 1, 0); + Map styles = getCellStyles(rows, 1, 0); - assertThat("Wrong number of style rules", styles.size(), is(equalTo(2))); - assertThat("The cell has a wrong font family style", - styles.get("font-family"), is(equalTo("serif"))); - } + assertThat("Wrong number of style rules", styles.size(), is(equalTo(2))); + assertThat("The cell has a wrong font family style", + styles.get("font-family"), is(equalTo("serif"))); + } - @Test - public void testRowHeaderDrink() throws IOException { - HtmlTable table = getTable(); + @Test + public void testRowHeaderDrink() throws IOException { + HtmlTable table = getTable(); - HtmlTableBody body = table.getBodies().get(0); + HtmlTableBody body = table.getBodies().get(0); - List rows = body.getRows(); + List rows = body.getRows(); - assertCell(rows, 1, 1, 1, 3, "Drink"); + assertCell(rows, 1, 1, 1, 3, "Drink"); - Map styles = getCellStyles(rows, 1, 1); + Map styles = getCellStyles(rows, 1, 1); - assertThat("Wrong number of style rules", styles.size(), is(equalTo(3))); - assertThat("The cell has a wrong font family style", - styles.get("font-family"), is(equalTo("serif"))); - assertThat("The cell has a wrong font style", styles.get("font-style"), - is(equalTo("oblique"))); - } + assertThat("Wrong number of style rules", styles.size(), is(equalTo(3))); + assertThat("The cell has a wrong font family style", + styles.get("font-family"), is(equalTo("serif"))); + assertThat("The cell has a wrong font style", styles.get("font-style"), + is(equalTo("oblique"))); + } - @Test - public void testRowHeaderBeverages() throws IOException { - HtmlTable table = getTable(); + @Test + public void testRowHeaderBeverages() throws IOException { + HtmlTable table = getTable(); - HtmlTableBody body = table.getBodies().get(0); + HtmlTableBody body = table.getBodies().get(0); - List rows = body.getRows(); + List rows = body.getRows(); - assertCell(rows, 3, 0, 1, 2, "Beverages"); + assertCell(rows, 3, 0, 1, 2, "Beverages"); - Map styles = getCellStyles(rows, 3, 0); + Map styles = getCellStyles(rows, 3, 0); - assertThat("Wrong number of style rules", styles.size(), is(equalTo(4))); - assertThat("The cell has a wrong font family style", - styles.get("font-family"), is(equalTo("serif"))); - assertThat("The cell has a wrong background color", - styles.get("background-color"), is(equalTo("#990000"))); - assertThat("The cell has a wrong background image", - styles.get("background-image"), is(equalTo("none"))); - } + assertThat("Wrong number of style rules", styles.size(), is(equalTo(4))); + assertThat("The cell has a wrong font family style", + styles.get("font-family"), is(equalTo("serif"))); + assertThat("The cell has a wrong background color", + styles.get("background-color"), is(equalTo("#990000"))); + assertThat("The cell has a wrong background image", + styles.get("background-image"), is(equalTo("none"))); + } - @Test - public void testRowHeaderBread() throws IOException { - HtmlTable table = getTable(); + @Test + public void testRowHeaderBread() throws IOException { + HtmlTable table = getTable(); - HtmlTableBody body = table.getBodies().get(0); + HtmlTableBody body = table.getBodies().get(0); - List rows = body.getRows(); + List rows = body.getRows(); - assertCell(rows, 7, 1, 1, 1, "Bread"); + assertCell(rows, 7, 1, 1, 1, "Bread"); - Map styles = getCellStyles(rows, 7, 1); + Map styles = getCellStyles(rows, 7, 1); - assertThat("Wrong number of style rules", styles.size(), is(equalTo(2))); - assertThat("The cell has a wrong font family style", - styles.get("font-family"), is(equalTo("serif"))); - } + assertThat("Wrong number of style rules", styles.size(), is(equalTo(2))); + assertThat("The cell has a wrong font family style", + styles.get("font-family"), is(equalTo("serif"))); + } - @Test - public void testMeasureCell() throws IOException { - HtmlTable table = getTable(); + @Test + public void testMeasureCell() throws IOException { + HtmlTable table = getTable(); - HtmlTableBody body = table.getBodies().get(0); + HtmlTableBody body = table.getBodies().get(0); - List rows = body.getRows(); + List rows = body.getRows(); - assertCell(rows, 3, 1, 1, 1, "$27,748.53"); + assertCell(rows, 3, 1, 1, 1, "$27,748.53"); - Map styles = getCellStyles(rows, 3, 1); + Map styles = getCellStyles(rows, 3, 1); - assertThat("Wrong number of style rules", styles.isEmpty(), is(true)); - } + assertThat("Wrong number of style rules", styles.isEmpty(), is(true)); + } - @Test - public void testMeasureCellMinus() throws IOException { - HtmlTable table = getTable(); + @Test + public void testMeasureCellMinus() throws IOException { + HtmlTable table = getTable(); - HtmlTableBody body = table.getBodies().get(0); + HtmlTableBody body = table.getBodies().get(0); - List rows = body.getRows(); + List rows = body.getRows(); - assertCell(rows, 3, 2, 1, 1, "$11,069.53"); + assertCell(rows, 3, 2, 1, 1, "$11,069.53"); - Map styles = getCellStyles(rows, 3, 2); + Map styles = getCellStyles(rows, 3, 2); - assertThat("Wrong number of style rules", styles.size(), is(equalTo(2))); - assertThat("The cell has a wrong foreground color", - styles.get("color"), is(equalTo("#ff0000"))); - assertThat("The cell has a wrong font style", - styles.get("font-weight"), is(equalTo("bold"))); - } + assertThat("Wrong number of style rules", styles.size(), is(equalTo(2))); + assertThat("The cell has a wrong foreground color", + styles.get("color"), is(equalTo("#ff0000"))); + assertThat("The cell has a wrong font style", + styles.get("font-weight"), is(equalTo("bold"))); + } } diff --git a/pivot4j-core/src/test/java/org/pivot4j/ui/property/SimplePropertyTest.java b/pivot4j-core/src/test/java/org/pivot4j/ui/property/SimplePropertyTest.java index 7599fe2c..f4065db3 100644 --- a/pivot4j-core/src/test/java/org/pivot4j/ui/property/SimplePropertyTest.java +++ b/pivot4j-core/src/test/java/org/pivot4j/ui/property/SimplePropertyTest.java @@ -25,57 +25,57 @@ public class SimplePropertyTest extends AbstractMockRenderTestCase { - @Test - public void testSimpleExpression() { - TableRenderContext context = createDummyRenderContext(); - context.setColIndex(2); - context.setRowIndex(1); + @Test + public void testSimpleExpression() { + TableRenderContext context = createDummyRenderContext(); + context.setColIndex(2); + context.setRowIndex(1); - RenderProperty property = new SimpleRenderProperty("label", - "(${rowIndex}, ${columnIndex})"); + RenderProperty property = new SimpleRenderProperty("label", + "(${rowIndex}, ${columnIndex})"); - String result = ObjectUtils.toString(property.getValue(context)); + String result = ObjectUtils.toString(property.getValue(context)); - assertThat("Wrong property value.", result, is(equalTo("(1, 2)"))); - } + assertThat("Wrong property value.", result, is(equalTo("(1, 2)"))); + } - @Test - public void testStateManagement() { - SimpleRenderProperty property = new SimpleRenderProperty("bgColor", - "red"); + @Test + public void testStateManagement() { + SimpleRenderProperty property = new SimpleRenderProperty("bgColor", + "red"); - Serializable state = property.saveState(); + Serializable state = property.saveState(); - SimpleRenderProperty property2 = new SimpleRenderProperty(); + SimpleRenderProperty property2 = new SimpleRenderProperty(); - property2.restoreState(state); + property2.restoreState(state); - assertThat("RenderProperty name has been changed.", - property2.getName(), is(equalTo(property.getName()))); - assertThat("RenderProperty value has been changed.", - property2.getValue(), is(equalTo(property.getValue()))); - } + assertThat("RenderProperty name has been changed.", + property2.getName(), is(equalTo(property.getName()))); + assertThat("RenderProperty value has been changed.", + property2.getValue(), is(equalTo(property.getValue()))); + } - @Test - public void testSettingsManagement() throws ConfigurationException { - SimpleRenderProperty property = new SimpleRenderProperty("bgColor", - "red"); + @Test + public void testSettingsManagement() throws ConfigurationException { + SimpleRenderProperty property = new SimpleRenderProperty("bgColor", + "red"); - XMLConfiguration configuration = new XMLConfiguration(); - configuration.setRootElementName("property"); + XMLConfiguration configuration = new XMLConfiguration(); + configuration.setRootElementName("property"); - property.saveSettings(configuration); + property.saveSettings(configuration); - SimpleRenderProperty property2 = new SimpleRenderProperty(); - property2.restoreSettings(configuration); + SimpleRenderProperty property2 = new SimpleRenderProperty(); + property2.restoreSettings(configuration); - assertThat("RenderProperty name has been changed.", - property2.getName(), is(equalTo(property.getName()))); - assertThat("RenderProperty value has been changed.", - property2.getValue(), is(equalTo(property.getValue()))); + assertThat("RenderProperty name has been changed.", + property2.getName(), is(equalTo(property.getName()))); + assertThat("RenderProperty value has been changed.", + property2.getValue(), is(equalTo(property.getValue()))); - System.out.println("Saved configuration : "); + System.out.println("Saved configuration : "); - configuration.save(System.out); - } + configuration.save(System.out); + } } diff --git a/pivot4j-core/src/test/java/org/pivot4j/util/RaggedMemberWrapperIT.java b/pivot4j-core/src/test/java/org/pivot4j/util/RaggedMemberWrapperIT.java index 6adec60b..492fa923 100644 --- a/pivot4j-core/src/test/java/org/pivot4j/util/RaggedMemberWrapperIT.java +++ b/pivot4j-core/src/test/java/org/pivot4j/util/RaggedMemberWrapperIT.java @@ -24,160 +24,160 @@ public class RaggedMemberWrapperIT extends AbstractIntegrationTestCase { - private Cube cube; - - private OlapUtils utils; - - private Member member; - - private Member childMember; - - /** - * @see org.pivot4j.AbstractIntegrationTestCase#setUp() - */ - @Override - public void setUp() throws Exception { - super.setUp(); - - this.cube = getDataSource().getConnection().getOlapSchema().getCubes() - .get("Sales Ragged"); - this.utils = new OlapUtils(cube); - this.member = OlapUtils.lookupMember("[Store].[Israel].[Tel Aviv]", - cube); - this.childMember = OlapUtils.lookupMember( - "[Store].[Israel].[Tel Aviv].[Store 23]", cube); - } - - /** - * @see org.pivot4j.AbstractIntegrationTestCase#tearDown() - */ - @Override - public void tearDown() throws Exception { - super.tearDown(); - - this.cube = null; - this.utils = null; - this.member = null; - this.childMember = null; - } - - /** - * @return the cube - */ - protected Cube getCube() { - return cube; - } - - /** - * @return the utils - */ - protected OlapUtils getUtils() { - return utils; - } - - /** - * @return the member - */ - protected Member getMember() { - return member; - } - - /** - * @return the childMember - */ - protected Member getChildMember() { - return childMember; - } - - @Test - public void testBaseMember() { - Member raggedMember = utils.wrapRaggedIfNecessary(member); - Member raggedChildMember = utils.wrapRaggedIfNecessary(childMember); - - assertThat("Invalid base member name.", raggedMember.getName(), - is("Tel Aviv")); - - assertThat("Invalid base member unique name.", - raggedMember.getUniqueName(), is("[Store].[Israel].[Tel Aviv]")); - assertThat("Invalid member depth.", raggedMember.getDepth(), is(3)); - - assertThat("Invalid base member name.", raggedChildMember.getName(), - is("Store 23")); - - assertThat("Invalid base member unique name.", - raggedChildMember.getUniqueName(), - is("[Store].[Israel].[Tel Aviv].[Store 23]")); - } - - @Test - public void testParentMember() { - Member raggedMember = utils.wrapRaggedIfNecessary(member); - Member parent = raggedMember.getParentMember(); - - assertThat("Parent member is null.", parent, is(notNullValue())); - assertThat("Parent member level is null.", parent.getLevel(), - is(notNullValue())); - assertThat("Invalid parent member unique name.", - parent.getUniqueName(), - is(equalTo("[Store].[Israel].[Israel]"))); - assertThat("Invalid member depth.", parent.getDepth(), is(equalTo(2))); - } - - @Test - public void testTopMember() { - Member raggedMember = utils.wrapRaggedIfNecessary(member); - Member parent = raggedMember.getParentMember().getParentMember(); - - assertThat("Top member is null.", parent, is(notNullValue())); - assertThat("Top member level is null.", parent.getLevel(), - is(notNullValue())); - assertThat("Invalid top member unique name.", parent.getUniqueName(), - is("[Store].[Israel]")); - assertThat("Invalid member depth.", parent.getDepth(), is(equalTo(1))); - } - - @Test - public void testAncestorMembers() { - Member raggedMember = utils.wrapRaggedIfNecessary(member); - - List ancestors = raggedMember.getAncestorMembers(); - - assertThat("Ancestor member list is null.", ancestors, - is(notNullValue())); - assertThat("Invalid number of ancestors.", ancestors.size(), - is(equalTo(3))); - - assertThat("Top level ancestor should be an all member.", ancestors - .get(2).isAll(), is(true)); - assertThat("Second level ancestor depth should be 1.", ancestors.get(1) - .getDepth(), is(equalTo(1))); - assertThat("Third level ancestor depth should be 2.", ancestors.get(0) - .getDepth(), is(equalTo(2))); - } - - @Test - public void testEquals() { - Member raggedMember = utils.wrapRaggedIfNecessary(member); - Member anotherRaggedMember = utils.wrapRaggedIfNecessary(member); - - assertThat("Wrapped member should be equal to the original.", - raggedMember.equals(member), is(true)); - assertThat("Members should be equal to each other.", - raggedMember.equals(anotherRaggedMember), is(true)); - assertThat( - "Parent members should be equal to each other.", - raggedMember.getParentMember().equals( - anotherRaggedMember.getParentMember()), is(true)); - } - - @Test - public void testRaggedMemberWrapper() { - Member raggedMember = utils.wrapRaggedIfNecessary(member); - Member raggedChildMember = utils.wrapRaggedIfNecessary(childMember); - - assertThat(member.getUniqueName() + " needs a ragged wrapper.", - raggedMember, is(instanceOf(RaggedMemberWrapper.class))); - assertThat(childMember.getUniqueName() + " needs a ragged wrapper.", - raggedChildMember, is(instanceOf(RaggedMemberWrapper.class))); - } + private Cube cube; + + private OlapUtils utils; + + private Member member; + + private Member childMember; + + /** + * @see org.pivot4j.AbstractIntegrationTestCase#setUp() + */ + @Override + public void setUp() throws Exception { + super.setUp(); + + this.cube = getDataSource().getConnection().getOlapSchema().getCubes() + .get("Sales Ragged"); + this.utils = new OlapUtils(cube); + this.member = OlapUtils.lookupMember("[Store].[Israel].[Tel Aviv]", + cube); + this.childMember = OlapUtils.lookupMember( + "[Store].[Israel].[Tel Aviv].[Store 23]", cube); + } + + /** + * @see org.pivot4j.AbstractIntegrationTestCase#tearDown() + */ + @Override + public void tearDown() throws Exception { + super.tearDown(); + + this.cube = null; + this.utils = null; + this.member = null; + this.childMember = null; + } + + /** + * @return the cube + */ + protected Cube getCube() { + return cube; + } + + /** + * @return the utils + */ + protected OlapUtils getUtils() { + return utils; + } + + /** + * @return the member + */ + protected Member getMember() { + return member; + } + + /** + * @return the childMember + */ + protected Member getChildMember() { + return childMember; + } + + @Test + public void testBaseMember() { + Member raggedMember = utils.wrapRaggedIfNecessary(member); + Member raggedChildMember = utils.wrapRaggedIfNecessary(childMember); + + assertThat("Invalid base member name.", raggedMember.getName(), + is("Tel Aviv")); + + assertThat("Invalid base member unique name.", + raggedMember.getUniqueName(), is("[Store].[Israel].[Tel Aviv]")); + assertThat("Invalid member depth.", raggedMember.getDepth(), is(3)); + + assertThat("Invalid base member name.", raggedChildMember.getName(), + is("Store 23")); + + assertThat("Invalid base member unique name.", + raggedChildMember.getUniqueName(), + is("[Store].[Israel].[Tel Aviv].[Store 23]")); + } + + @Test + public void testParentMember() { + Member raggedMember = utils.wrapRaggedIfNecessary(member); + Member parent = raggedMember.getParentMember(); + + assertThat("Parent member is null.", parent, is(notNullValue())); + assertThat("Parent member level is null.", parent.getLevel(), + is(notNullValue())); + assertThat("Invalid parent member unique name.", + parent.getUniqueName(), + is(equalTo("[Store].[Israel].[Israel]"))); + assertThat("Invalid member depth.", parent.getDepth(), is(equalTo(2))); + } + + @Test + public void testTopMember() { + Member raggedMember = utils.wrapRaggedIfNecessary(member); + Member parent = raggedMember.getParentMember().getParentMember(); + + assertThat("Top member is null.", parent, is(notNullValue())); + assertThat("Top member level is null.", parent.getLevel(), + is(notNullValue())); + assertThat("Invalid top member unique name.", parent.getUniqueName(), + is("[Store].[Israel]")); + assertThat("Invalid member depth.", parent.getDepth(), is(equalTo(1))); + } + + @Test + public void testAncestorMembers() { + Member raggedMember = utils.wrapRaggedIfNecessary(member); + + List ancestors = raggedMember.getAncestorMembers(); + + assertThat("Ancestor member list is null.", ancestors, + is(notNullValue())); + assertThat("Invalid number of ancestors.", ancestors.size(), + is(equalTo(3))); + + assertThat("Top level ancestor should be an all member.", ancestors + .get(2).isAll(), is(true)); + assertThat("Second level ancestor depth should be 1.", ancestors.get(1) + .getDepth(), is(equalTo(1))); + assertThat("Third level ancestor depth should be 2.", ancestors.get(0) + .getDepth(), is(equalTo(2))); + } + + @Test + public void testEquals() { + Member raggedMember = utils.wrapRaggedIfNecessary(member); + Member anotherRaggedMember = utils.wrapRaggedIfNecessary(member); + + assertThat("Wrapped member should be equal to the original.", + raggedMember.equals(member), is(true)); + assertThat("Members should be equal to each other.", + raggedMember.equals(anotherRaggedMember), is(true)); + assertThat( + "Parent members should be equal to each other.", + raggedMember.getParentMember().equals( + anotherRaggedMember.getParentMember()), is(true)); + } + + @Test + public void testRaggedMemberWrapper() { + Member raggedMember = utils.wrapRaggedIfNecessary(member); + Member raggedChildMember = utils.wrapRaggedIfNecessary(childMember); + + assertThat(member.getUniqueName() + " needs a ragged wrapper.", + raggedMember, is(instanceOf(RaggedMemberWrapper.class))); + assertThat(childMember.getUniqueName() + " needs a ragged wrapper.", + raggedChildMember, is(instanceOf(RaggedMemberWrapper.class))); + } } diff --git a/pivot4j-core/src/test/resources/log4j2-test.xml b/pivot4j-core/src/test/resources/log4j2-test.xml index 35cbd784..e3999ce5 100644 --- a/pivot4j-core/src/test/resources/log4j2-test.xml +++ b/pivot4j-core/src/test/resources/log4j2-test.xml @@ -1,18 +1,18 @@ - - - - - + + + + + - - - - + + + + - - - - + + + + \ No newline at end of file diff --git a/pivot4j-core/src/test/resources/mondrian.properties b/pivot4j-core/src/test/resources/mondrian.properties index 2e3194dd..c43e4483 100644 --- a/pivot4j-core/src/test/resources/mondrian.properties +++ b/pivot4j-core/src/test/resources/mondrian.properties @@ -5,6 +5,22 @@ mondrian.native.topcount.enable=true mondrian.native.filter.enable=true # mondrian.properties -mondrian.result.limit=50000 +mondrian.result.limit=500000 mondrian.rolap.ignoreInvalidMembers=true + +# Caching Parameters +mondrian.expCache.enable=false +mondrian.rolap.EnableRolapCubeMemberCache=false +mondrian.rolap.star.disableCaching=true +mondrian.rolap.star.disableLocalSegmentCache=true + +# Default is true +mondrian.util.memoryMonitor.enable=false + +#Defines how a null Member is represented in the result output. MSAS 2000 shows empty value while MSAS 2005 shows "(null)" +mondrian.olap.NullMemberRepresentation= + +#absolute - The SOLVE_ORDER value is absolute regardless of where it is defined; e.g. a query defined calculated member with a SOLVE_ORDER of 1 always takes precedence over a cube defined value of 2. +#scoped - Cube calculated members are resolved before any session scope calculated members, and session scope members are resolved before any query defined calculation. The SOLVE_ORDER value only applies within the scope in which it was defined. +mondrian.rolap.SolveOrderMode=scoped \ No newline at end of file diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/basic-false-false-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/basic-false-false-false-result.html index cae501ea..1737dc6d 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/basic-false-false-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/basic-false-false-false-result.html @@ -1,1026 +1,1026 @@
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - All Gender - - F - - M -
      - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - All Products - - All Marital Status - - 266,773 - - 225,627.23 - - 565,238.13 - - 131,558 - - 111,777.48 - - 280,226.21 - - 135,215 - - 113,849.75 - - 285,011.92 -
      - Drink - - All Marital Status - - 24,597 - - 19,477.23 - - 48,836.21 - - 12,202 - - 9,751.10 - - 24,457.37 - - 12,395 - - 9,726.14 - - 24,378.84 -
      - Food - - All Marital Status - - 191,940 - - 163,270.72 - - 409,035.59 - - 94,814 - - 80,993.45 - - 203,094.17 - - 97,126 - - 82,277.27 - - 205,941.42 -
      - Baked Goods - - All Marital Status - - 7,870 - - 6,564.09 - - 16,455.43 - - 3,771 - - 3,164.76 - - 7,938.38 - - 4,099 - - 3,399.34 - - 8,517.05 -
      - Baking Goods - - All Marital Status - - 20,245 - - 15,370.61 - - 38,670.41 - - 9,841 - - 7,389.74 - - 18,608.22 - - 10,404 - - 7,980.87 - - 20,062.19 -
      - Baking Goods - - All Marital Status - - 8,357 - - 6,123.32 - - 15,446.69 - - 4,005 - - 2,907.70 - - 7,313.61 - - 4,352 - - 3,215.62 - - 8,133.08 -
      - M - - 4,167 - - 3,044.62 - - 7,656.25 - - 2,028 - - 1,469.66 - - 3,711.91 - - 2,139 - - 1,574.96 - - 3,944.34 -
      - S - - 4,190 - - 3,078.70 - - 7,790.44 - - 1,977 - - 1,438.04 - - 3,601.70 - - 2,213 - - 1,640.66 - - 4,188.74 -
      - Jams and Jellies - - All Marital Status - - 11,888 - - 9,247.29 - - 23,223.72 - - 5,836 - - 4,482.04 - - 11,294.61 - - 6,052 - - 4,765.25 - - 11,929.11 -
      - Breakfast Foods - - All Marital Status - - 3,317 - - 2,756.80 - - 6,941.46 - - 1,821 - - 1,522.93 - - 3,840.30 - - 1,496 - - 1,233.87 - - 3,101.16 -
      - Canned Foods - - All Marital Status - - 19,026 - - 15,894.53 - - 39,774.34 - - 9,407 - - 7,942.57 - - 19,864.15 - - 9,619 - - 7,951.97 - - 19,910.19 -
      - Canned Products - - All Marital Status - - 1,812 - - 1,317.13 - - 3,314.52 - - 867 - - 613.76 - - 1,551.30 - - 945 - - 703.37 - - 1,763.22 -
      - Dairy - - All Marital Status - - 12,885 - - 12,228.85 - - 30,508.85 - - 6,513 - - 6,253.73 - - 15,603.84 - - 6,372 - - 5,975.12 - - 14,905.01 -
      - Deli - - All Marital Status - - 12,037 - - 10,108.87 - - 25,318.93 - - 5,990 - - 5,022.05 - - 12,592.39 - - 6,047 - - 5,086.82 - - 12,726.54 -
      - Eggs - - All Marital Status - - 4,132 - - 3,684.90 - - 9,200.76 - - 2,001 - - 1,746.06 - - 4,355.68 - - 2,131 - - 1,938.84 - - 4,845.08 -
      - Frozen Foods - - All Marital Status - - 26,655 - - 22,030.66 - - 55,207.50 - - 13,011 - - 10,843.01 - - 27,168.52 - - 13,644 - - 11,187.65 - - 28,038.98 -
      - Meat - - All Marital Status - - 1,714 - - 1,465.42 - - 3,669.89 - - 841 - - 716.84 - - 1,797.60 - - 873 - - 748.59 - - 1,872.29 -
      - Produce - - All Marital Status - - 37,792 - - 32,831.33 - - 82,248.42 - - 18,713 - - 16,403.72 - - 41,069.39 - - 19,079 - - 16,427.61 - - 41,179.03 -
      - Seafood - - All Marital Status - - 1,764 - - 1,520.70 - - 3,809.14 - - 947 - - 836.19 - - 2,095.55 - - 817 - - 684.51 - - 1,713.59 -
      - Snack Foods - - All Marital Status - - 30,545 - - 26,963.34 - - 67,609.82 - - 14,936 - - 13,160.27 - - 33,120.45 - - 15,609 - - 13,803.07 - - 34,489.37 -
      - Snacks - - All Marital Status - - 6,884 - - 5,827.58 - - 14,550.05 - - 3,459 - - 2,960.73 - - 7,430.30 - - 3,425 - - 2,866.86 - - 7,119.75 -
      - Starchy Foods - - All Marital Status - - 5,262 - - 4,705.91 - - 11,756.07 - - 2,696 - - 2,417.11 - - 6,058.10 - - 2,566 - - 2,288.79 - - 5,697.97 -
      - Non-Consumable - - All Marital Status - - 50,236 - - 42,879.28 - - 107,366.33 - - 24,542 - - 21,032.93 - - 52,674.67 - - 25,694 - - 21,846.35 - - 54,691.66 -
      - Carousel - - All Marital Status - - 841 - - 595.97 - - 1,500.11 - - 368 - - 258.40 - - 655.55 - - 473 - - 337.57 - - 844.56 -
      - Checkout - - All Marital Status - - 1,779 - - 1,525.04 - - 3,767.71 - - 887 - - 755.83 - - 1,874.82 - - 892 - - 769.21 - - 1,892.89 -
      - Health and Hygiene - - All Marital Status - - 16,284 - - 12,972.99 - - 32,571.86 - - 7,841 - - 6,308.73 - - 15,819.73 - - 8,443 - - 6,664.25 - - 16,752.13 -
      - Household - - All Marital Status - - 27,038 - - 24,170.73 - - 60,469.89 - - 13,278 - - 11,876.49 - - 29,741.49 - - 13,760 - - 12,294.24 - - 30,728.40 -
      - Periodicals - - All Marital Status - - 4,294 - - 3,614.55 - - 9,056.76 - - 2,168 - - 1,833.48 - - 4,583.08 - - 2,126 - - 1,781.08 - - 4,473.68 -
      +   + + All Gender + + F + + M +
      + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + All Products + + All Marital Status + + 266,773 + + 225,627.23 + + 565,238.13 + + 131,558 + + 111,777.48 + + 280,226.21 + + 135,215 + + 113,849.75 + + 285,011.92 +
      + Drink + + All Marital Status + + 24,597 + + 19,477.23 + + 48,836.21 + + 12,202 + + 9,751.10 + + 24,457.37 + + 12,395 + + 9,726.14 + + 24,378.84 +
      + Food + + All Marital Status + + 191,940 + + 163,270.72 + + 409,035.59 + + 94,814 + + 80,993.45 + + 203,094.17 + + 97,126 + + 82,277.27 + + 205,941.42 +
      + Baked Goods + + All Marital Status + + 7,870 + + 6,564.09 + + 16,455.43 + + 3,771 + + 3,164.76 + + 7,938.38 + + 4,099 + + 3,399.34 + + 8,517.05 +
      + Baking Goods + + All Marital Status + + 20,245 + + 15,370.61 + + 38,670.41 + + 9,841 + + 7,389.74 + + 18,608.22 + + 10,404 + + 7,980.87 + + 20,062.19 +
      + Baking Goods + + All Marital Status + + 8,357 + + 6,123.32 + + 15,446.69 + + 4,005 + + 2,907.70 + + 7,313.61 + + 4,352 + + 3,215.62 + + 8,133.08 +
      + M + + 4,167 + + 3,044.62 + + 7,656.25 + + 2,028 + + 1,469.66 + + 3,711.91 + + 2,139 + + 1,574.96 + + 3,944.34 +
      + S + + 4,190 + + 3,078.70 + + 7,790.44 + + 1,977 + + 1,438.04 + + 3,601.70 + + 2,213 + + 1,640.66 + + 4,188.74 +
      + Jams and Jellies + + All Marital Status + + 11,888 + + 9,247.29 + + 23,223.72 + + 5,836 + + 4,482.04 + + 11,294.61 + + 6,052 + + 4,765.25 + + 11,929.11 +
      + Breakfast Foods + + All Marital Status + + 3,317 + + 2,756.80 + + 6,941.46 + + 1,821 + + 1,522.93 + + 3,840.30 + + 1,496 + + 1,233.87 + + 3,101.16 +
      + Canned Foods + + All Marital Status + + 19,026 + + 15,894.53 + + 39,774.34 + + 9,407 + + 7,942.57 + + 19,864.15 + + 9,619 + + 7,951.97 + + 19,910.19 +
      + Canned Products + + All Marital Status + + 1,812 + + 1,317.13 + + 3,314.52 + + 867 + + 613.76 + + 1,551.30 + + 945 + + 703.37 + + 1,763.22 +
      + Dairy + + All Marital Status + + 12,885 + + 12,228.85 + + 30,508.85 + + 6,513 + + 6,253.73 + + 15,603.84 + + 6,372 + + 5,975.12 + + 14,905.01 +
      + Deli + + All Marital Status + + 12,037 + + 10,108.87 + + 25,318.93 + + 5,990 + + 5,022.05 + + 12,592.39 + + 6,047 + + 5,086.82 + + 12,726.54 +
      + Eggs + + All Marital Status + + 4,132 + + 3,684.90 + + 9,200.76 + + 2,001 + + 1,746.06 + + 4,355.68 + + 2,131 + + 1,938.84 + + 4,845.08 +
      + Frozen Foods + + All Marital Status + + 26,655 + + 22,030.66 + + 55,207.50 + + 13,011 + + 10,843.01 + + 27,168.52 + + 13,644 + + 11,187.65 + + 28,038.98 +
      + Meat + + All Marital Status + + 1,714 + + 1,465.42 + + 3,669.89 + + 841 + + 716.84 + + 1,797.60 + + 873 + + 748.59 + + 1,872.29 +
      + Produce + + All Marital Status + + 37,792 + + 32,831.33 + + 82,248.42 + + 18,713 + + 16,403.72 + + 41,069.39 + + 19,079 + + 16,427.61 + + 41,179.03 +
      + Seafood + + All Marital Status + + 1,764 + + 1,520.70 + + 3,809.14 + + 947 + + 836.19 + + 2,095.55 + + 817 + + 684.51 + + 1,713.59 +
      + Snack Foods + + All Marital Status + + 30,545 + + 26,963.34 + + 67,609.82 + + 14,936 + + 13,160.27 + + 33,120.45 + + 15,609 + + 13,803.07 + + 34,489.37 +
      + Snacks + + All Marital Status + + 6,884 + + 5,827.58 + + 14,550.05 + + 3,459 + + 2,960.73 + + 7,430.30 + + 3,425 + + 2,866.86 + + 7,119.75 +
      + Starchy Foods + + All Marital Status + + 5,262 + + 4,705.91 + + 11,756.07 + + 2,696 + + 2,417.11 + + 6,058.10 + + 2,566 + + 2,288.79 + + 5,697.97 +
      + Non-Consumable + + All Marital Status + + 50,236 + + 42,879.28 + + 107,366.33 + + 24,542 + + 21,032.93 + + 52,674.67 + + 25,694 + + 21,846.35 + + 54,691.66 +
      + Carousel + + All Marital Status + + 841 + + 595.97 + + 1,500.11 + + 368 + + 258.40 + + 655.55 + + 473 + + 337.57 + + 844.56 +
      + Checkout + + All Marital Status + + 1,779 + + 1,525.04 + + 3,767.71 + + 887 + + 755.83 + + 1,874.82 + + 892 + + 769.21 + + 1,892.89 +
      + Health and Hygiene + + All Marital Status + + 16,284 + + 12,972.99 + + 32,571.86 + + 7,841 + + 6,308.73 + + 15,819.73 + + 8,443 + + 6,664.25 + + 16,752.13 +
      + Household + + All Marital Status + + 27,038 + + 24,170.73 + + 60,469.89 + + 13,278 + + 11,876.49 + + 29,741.49 + + 13,760 + + 12,294.24 + + 30,728.40 +
      + Periodicals + + All Marital Status + + 4,294 + + 3,614.55 + + 9,056.76 + + 2,168 + + 1,833.48 + + 4,583.08 + + 2,126 + + 1,781.08 + + 4,473.68 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/basic-false-false-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/basic-false-false-true-result.html index dc727c3c..0c2957a0 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/basic-false-false-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/basic-false-false-true-result.html @@ -1,1046 +1,1046 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - All Gender - - All Gender -
      - F - - M -
      - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - All Products - - All Marital Status - - 266,773 - - 225,627.23 - - 565,238.13 - - 131,558 - - 111,777.48 - - 280,226.21 - - 135,215 - - 113,849.75 - - 285,011.92 -
      - All Products - - Drink - - All Marital Status - - 24,597 - - 19,477.23 - - 48,836.21 - - 12,202 - - 9,751.10 - - 24,457.37 - - 12,395 - - 9,726.14 - - 24,378.84 -
      - Food - - All Marital Status - - 191,940 - - 163,270.72 - - 409,035.59 - - 94,814 - - 80,993.45 - - 203,094.17 - - 97,126 - - 82,277.27 - - 205,941.42 -
      - Food - - Baked Goods - - All Marital Status - - 7,870 - - 6,564.09 - - 16,455.43 - - 3,771 - - 3,164.76 - - 7,938.38 - - 4,099 - - 3,399.34 - - 8,517.05 -
      - Baking Goods - - All Marital Status - - 20,245 - - 15,370.61 - - 38,670.41 - - 9,841 - - 7,389.74 - - 18,608.22 - - 10,404 - - 7,980.87 - - 20,062.19 -
      - Baking Goods - - Baking Goods - - All Marital Status - - 8,357 - - 6,123.32 - - 15,446.69 - - 4,005 - - 2,907.70 - - 7,313.61 - - 4,352 - - 3,215.62 - - 8,133.08 -
      - All Marital Status - - M - - 4,167 - - 3,044.62 - - 7,656.25 - - 2,028 - - 1,469.66 - - 3,711.91 - - 2,139 - - 1,574.96 - - 3,944.34 -
      - S - - 4,190 - - 3,078.70 - - 7,790.44 - - 1,977 - - 1,438.04 - - 3,601.70 - - 2,213 - - 1,640.66 - - 4,188.74 -
      - Jams and Jellies - - All Marital Status - - 11,888 - - 9,247.29 - - 23,223.72 - - 5,836 - - 4,482.04 - - 11,294.61 - - 6,052 - - 4,765.25 - - 11,929.11 -
      - Breakfast Foods - - All Marital Status - - 3,317 - - 2,756.80 - - 6,941.46 - - 1,821 - - 1,522.93 - - 3,840.30 - - 1,496 - - 1,233.87 - - 3,101.16 -
      - Canned Foods - - All Marital Status - - 19,026 - - 15,894.53 - - 39,774.34 - - 9,407 - - 7,942.57 - - 19,864.15 - - 9,619 - - 7,951.97 - - 19,910.19 -
      - Canned Products - - All Marital Status - - 1,812 - - 1,317.13 - - 3,314.52 - - 867 - - 613.76 - - 1,551.30 - - 945 - - 703.37 - - 1,763.22 -
      - Dairy - - All Marital Status - - 12,885 - - 12,228.85 - - 30,508.85 - - 6,513 - - 6,253.73 - - 15,603.84 - - 6,372 - - 5,975.12 - - 14,905.01 -
      - Deli - - All Marital Status - - 12,037 - - 10,108.87 - - 25,318.93 - - 5,990 - - 5,022.05 - - 12,592.39 - - 6,047 - - 5,086.82 - - 12,726.54 -
      - Eggs - - All Marital Status - - 4,132 - - 3,684.90 - - 9,200.76 - - 2,001 - - 1,746.06 - - 4,355.68 - - 2,131 - - 1,938.84 - - 4,845.08 -
      - Frozen Foods - - All Marital Status - - 26,655 - - 22,030.66 - - 55,207.50 - - 13,011 - - 10,843.01 - - 27,168.52 - - 13,644 - - 11,187.65 - - 28,038.98 -
      - Meat - - All Marital Status - - 1,714 - - 1,465.42 - - 3,669.89 - - 841 - - 716.84 - - 1,797.60 - - 873 - - 748.59 - - 1,872.29 -
      - Produce - - All Marital Status - - 37,792 - - 32,831.33 - - 82,248.42 - - 18,713 - - 16,403.72 - - 41,069.39 - - 19,079 - - 16,427.61 - - 41,179.03 -
      - Seafood - - All Marital Status - - 1,764 - - 1,520.70 - - 3,809.14 - - 947 - - 836.19 - - 2,095.55 - - 817 - - 684.51 - - 1,713.59 -
      - Snack Foods - - All Marital Status - - 30,545 - - 26,963.34 - - 67,609.82 - - 14,936 - - 13,160.27 - - 33,120.45 - - 15,609 - - 13,803.07 - - 34,489.37 -
      - Snacks - - All Marital Status - - 6,884 - - 5,827.58 - - 14,550.05 - - 3,459 - - 2,960.73 - - 7,430.30 - - 3,425 - - 2,866.86 - - 7,119.75 -
      - Starchy Foods - - All Marital Status - - 5,262 - - 4,705.91 - - 11,756.07 - - 2,696 - - 2,417.11 - - 6,058.10 - - 2,566 - - 2,288.79 - - 5,697.97 -
      - Non-Consumable - - All Marital Status - - 50,236 - - 42,879.28 - - 107,366.33 - - 24,542 - - 21,032.93 - - 52,674.67 - - 25,694 - - 21,846.35 - - 54,691.66 -
      - Non-Consumable - - Carousel - - All Marital Status - - 841 - - 595.97 - - 1,500.11 - - 368 - - 258.40 - - 655.55 - - 473 - - 337.57 - - 844.56 -
      - Checkout - - All Marital Status - - 1,779 - - 1,525.04 - - 3,767.71 - - 887 - - 755.83 - - 1,874.82 - - 892 - - 769.21 - - 1,892.89 -
      - Health and Hygiene - - All Marital Status - - 16,284 - - 12,972.99 - - 32,571.86 - - 7,841 - - 6,308.73 - - 15,819.73 - - 8,443 - - 6,664.25 - - 16,752.13 -
      - Household - - All Marital Status - - 27,038 - - 24,170.73 - - 60,469.89 - - 13,278 - - 11,876.49 - - 29,741.49 - - 13,760 - - 12,294.24 - - 30,728.40 -
      - Periodicals - - All Marital Status - - 4,294 - - 3,614.55 - - 9,056.76 - - 2,168 - - 1,833.48 - - 4,583.08 - - 2,126 - - 1,781.08 - - 4,473.68 -
      +   + + All Gender + + All Gender +
      + F + + M +
      + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + All Products + + All Marital Status + + 266,773 + + 225,627.23 + + 565,238.13 + + 131,558 + + 111,777.48 + + 280,226.21 + + 135,215 + + 113,849.75 + + 285,011.92 +
      + All Products + + Drink + + All Marital Status + + 24,597 + + 19,477.23 + + 48,836.21 + + 12,202 + + 9,751.10 + + 24,457.37 + + 12,395 + + 9,726.14 + + 24,378.84 +
      + Food + + All Marital Status + + 191,940 + + 163,270.72 + + 409,035.59 + + 94,814 + + 80,993.45 + + 203,094.17 + + 97,126 + + 82,277.27 + + 205,941.42 +
      + Food + + Baked Goods + + All Marital Status + + 7,870 + + 6,564.09 + + 16,455.43 + + 3,771 + + 3,164.76 + + 7,938.38 + + 4,099 + + 3,399.34 + + 8,517.05 +
      + Baking Goods + + All Marital Status + + 20,245 + + 15,370.61 + + 38,670.41 + + 9,841 + + 7,389.74 + + 18,608.22 + + 10,404 + + 7,980.87 + + 20,062.19 +
      + Baking Goods + + Baking Goods + + All Marital Status + + 8,357 + + 6,123.32 + + 15,446.69 + + 4,005 + + 2,907.70 + + 7,313.61 + + 4,352 + + 3,215.62 + + 8,133.08 +
      + All Marital Status + + M + + 4,167 + + 3,044.62 + + 7,656.25 + + 2,028 + + 1,469.66 + + 3,711.91 + + 2,139 + + 1,574.96 + + 3,944.34 +
      + S + + 4,190 + + 3,078.70 + + 7,790.44 + + 1,977 + + 1,438.04 + + 3,601.70 + + 2,213 + + 1,640.66 + + 4,188.74 +
      + Jams and Jellies + + All Marital Status + + 11,888 + + 9,247.29 + + 23,223.72 + + 5,836 + + 4,482.04 + + 11,294.61 + + 6,052 + + 4,765.25 + + 11,929.11 +
      + Breakfast Foods + + All Marital Status + + 3,317 + + 2,756.80 + + 6,941.46 + + 1,821 + + 1,522.93 + + 3,840.30 + + 1,496 + + 1,233.87 + + 3,101.16 +
      + Canned Foods + + All Marital Status + + 19,026 + + 15,894.53 + + 39,774.34 + + 9,407 + + 7,942.57 + + 19,864.15 + + 9,619 + + 7,951.97 + + 19,910.19 +
      + Canned Products + + All Marital Status + + 1,812 + + 1,317.13 + + 3,314.52 + + 867 + + 613.76 + + 1,551.30 + + 945 + + 703.37 + + 1,763.22 +
      + Dairy + + All Marital Status + + 12,885 + + 12,228.85 + + 30,508.85 + + 6,513 + + 6,253.73 + + 15,603.84 + + 6,372 + + 5,975.12 + + 14,905.01 +
      + Deli + + All Marital Status + + 12,037 + + 10,108.87 + + 25,318.93 + + 5,990 + + 5,022.05 + + 12,592.39 + + 6,047 + + 5,086.82 + + 12,726.54 +
      + Eggs + + All Marital Status + + 4,132 + + 3,684.90 + + 9,200.76 + + 2,001 + + 1,746.06 + + 4,355.68 + + 2,131 + + 1,938.84 + + 4,845.08 +
      + Frozen Foods + + All Marital Status + + 26,655 + + 22,030.66 + + 55,207.50 + + 13,011 + + 10,843.01 + + 27,168.52 + + 13,644 + + 11,187.65 + + 28,038.98 +
      + Meat + + All Marital Status + + 1,714 + + 1,465.42 + + 3,669.89 + + 841 + + 716.84 + + 1,797.60 + + 873 + + 748.59 + + 1,872.29 +
      + Produce + + All Marital Status + + 37,792 + + 32,831.33 + + 82,248.42 + + 18,713 + + 16,403.72 + + 41,069.39 + + 19,079 + + 16,427.61 + + 41,179.03 +
      + Seafood + + All Marital Status + + 1,764 + + 1,520.70 + + 3,809.14 + + 947 + + 836.19 + + 2,095.55 + + 817 + + 684.51 + + 1,713.59 +
      + Snack Foods + + All Marital Status + + 30,545 + + 26,963.34 + + 67,609.82 + + 14,936 + + 13,160.27 + + 33,120.45 + + 15,609 + + 13,803.07 + + 34,489.37 +
      + Snacks + + All Marital Status + + 6,884 + + 5,827.58 + + 14,550.05 + + 3,459 + + 2,960.73 + + 7,430.30 + + 3,425 + + 2,866.86 + + 7,119.75 +
      + Starchy Foods + + All Marital Status + + 5,262 + + 4,705.91 + + 11,756.07 + + 2,696 + + 2,417.11 + + 6,058.10 + + 2,566 + + 2,288.79 + + 5,697.97 +
      + Non-Consumable + + All Marital Status + + 50,236 + + 42,879.28 + + 107,366.33 + + 24,542 + + 21,032.93 + + 52,674.67 + + 25,694 + + 21,846.35 + + 54,691.66 +
      + Non-Consumable + + Carousel + + All Marital Status + + 841 + + 595.97 + + 1,500.11 + + 368 + + 258.40 + + 655.55 + + 473 + + 337.57 + + 844.56 +
      + Checkout + + All Marital Status + + 1,779 + + 1,525.04 + + 3,767.71 + + 887 + + 755.83 + + 1,874.82 + + 892 + + 769.21 + + 1,892.89 +
      + Health and Hygiene + + All Marital Status + + 16,284 + + 12,972.99 + + 32,571.86 + + 7,841 + + 6,308.73 + + 15,819.73 + + 8,443 + + 6,664.25 + + 16,752.13 +
      + Household + + All Marital Status + + 27,038 + + 24,170.73 + + 60,469.89 + + 13,278 + + 11,876.49 + + 29,741.49 + + 13,760 + + 12,294.24 + + 30,728.40 +
      + Periodicals + + All Marital Status + + 4,294 + + 3,614.55 + + 9,056.76 + + 2,168 + + 1,833.48 + + 4,583.08 + + 2,126 + + 1,781.08 + + 4,473.68 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/basic-false-true-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/basic-false-true-false-result.html index f4b9da1d..6cf8c59b 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/basic-false-true-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/basic-false-true-false-result.html @@ -1,1051 +1,1051 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Gender -
      - All Gender - - F - - M -
      - Measures - - Measures - - Measures -
      - Promotion Media - - Product - - Marital Status - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - All Products - - All Marital Status - - 266,773 - - 225,627.23 - - 565,238.13 - - 131,558 - - 111,777.48 - - 280,226.21 - - 135,215 - - 113,849.75 - - 285,011.92 -
      - Drink - - All Marital Status - - 24,597 - - 19,477.23 - - 48,836.21 - - 12,202 - - 9,751.10 - - 24,457.37 - - 12,395 - - 9,726.14 - - 24,378.84 -
      - Food - - All Marital Status - - 191,940 - - 163,270.72 - - 409,035.59 - - 94,814 - - 80,993.45 - - 203,094.17 - - 97,126 - - 82,277.27 - - 205,941.42 -
      - Baked Goods - - All Marital Status - - 7,870 - - 6,564.09 - - 16,455.43 - - 3,771 - - 3,164.76 - - 7,938.38 - - 4,099 - - 3,399.34 - - 8,517.05 -
      - Baking Goods - - All Marital Status - - 20,245 - - 15,370.61 - - 38,670.41 - - 9,841 - - 7,389.74 - - 18,608.22 - - 10,404 - - 7,980.87 - - 20,062.19 -
      - Baking Goods - - All Marital Status - - 8,357 - - 6,123.32 - - 15,446.69 - - 4,005 - - 2,907.70 - - 7,313.61 - - 4,352 - - 3,215.62 - - 8,133.08 -
      - M - - 4,167 - - 3,044.62 - - 7,656.25 - - 2,028 - - 1,469.66 - - 3,711.91 - - 2,139 - - 1,574.96 - - 3,944.34 -
      - S - - 4,190 - - 3,078.70 - - 7,790.44 - - 1,977 - - 1,438.04 - - 3,601.70 - - 2,213 - - 1,640.66 - - 4,188.74 -
      - Jams and Jellies - - All Marital Status - - 11,888 - - 9,247.29 - - 23,223.72 - - 5,836 - - 4,482.04 - - 11,294.61 - - 6,052 - - 4,765.25 - - 11,929.11 -
      - Breakfast Foods - - All Marital Status - - 3,317 - - 2,756.80 - - 6,941.46 - - 1,821 - - 1,522.93 - - 3,840.30 - - 1,496 - - 1,233.87 - - 3,101.16 -
      - Canned Foods - - All Marital Status - - 19,026 - - 15,894.53 - - 39,774.34 - - 9,407 - - 7,942.57 - - 19,864.15 - - 9,619 - - 7,951.97 - - 19,910.19 -
      - Canned Products - - All Marital Status - - 1,812 - - 1,317.13 - - 3,314.52 - - 867 - - 613.76 - - 1,551.30 - - 945 - - 703.37 - - 1,763.22 -
      - Dairy - - All Marital Status - - 12,885 - - 12,228.85 - - 30,508.85 - - 6,513 - - 6,253.73 - - 15,603.84 - - 6,372 - - 5,975.12 - - 14,905.01 -
      - Deli - - All Marital Status - - 12,037 - - 10,108.87 - - 25,318.93 - - 5,990 - - 5,022.05 - - 12,592.39 - - 6,047 - - 5,086.82 - - 12,726.54 -
      - Eggs - - All Marital Status - - 4,132 - - 3,684.90 - - 9,200.76 - - 2,001 - - 1,746.06 - - 4,355.68 - - 2,131 - - 1,938.84 - - 4,845.08 -
      - Frozen Foods - - All Marital Status - - 26,655 - - 22,030.66 - - 55,207.50 - - 13,011 - - 10,843.01 - - 27,168.52 - - 13,644 - - 11,187.65 - - 28,038.98 -
      - Meat - - All Marital Status - - 1,714 - - 1,465.42 - - 3,669.89 - - 841 - - 716.84 - - 1,797.60 - - 873 - - 748.59 - - 1,872.29 -
      - Produce - - All Marital Status - - 37,792 - - 32,831.33 - - 82,248.42 - - 18,713 - - 16,403.72 - - 41,069.39 - - 19,079 - - 16,427.61 - - 41,179.03 -
      - Seafood - - All Marital Status - - 1,764 - - 1,520.70 - - 3,809.14 - - 947 - - 836.19 - - 2,095.55 - - 817 - - 684.51 - - 1,713.59 -
      - Snack Foods - - All Marital Status - - 30,545 - - 26,963.34 - - 67,609.82 - - 14,936 - - 13,160.27 - - 33,120.45 - - 15,609 - - 13,803.07 - - 34,489.37 -
      - Snacks - - All Marital Status - - 6,884 - - 5,827.58 - - 14,550.05 - - 3,459 - - 2,960.73 - - 7,430.30 - - 3,425 - - 2,866.86 - - 7,119.75 -
      - Starchy Foods - - All Marital Status - - 5,262 - - 4,705.91 - - 11,756.07 - - 2,696 - - 2,417.11 - - 6,058.10 - - 2,566 - - 2,288.79 - - 5,697.97 -
      - Non-Consumable - - All Marital Status - - 50,236 - - 42,879.28 - - 107,366.33 - - 24,542 - - 21,032.93 - - 52,674.67 - - 25,694 - - 21,846.35 - - 54,691.66 -
      - Carousel - - All Marital Status - - 841 - - 595.97 - - 1,500.11 - - 368 - - 258.40 - - 655.55 - - 473 - - 337.57 - - 844.56 -
      - Checkout - - All Marital Status - - 1,779 - - 1,525.04 - - 3,767.71 - - 887 - - 755.83 - - 1,874.82 - - 892 - - 769.21 - - 1,892.89 -
      - Health and Hygiene - - All Marital Status - - 16,284 - - 12,972.99 - - 32,571.86 - - 7,841 - - 6,308.73 - - 15,819.73 - - 8,443 - - 6,664.25 - - 16,752.13 -
      - Household - - All Marital Status - - 27,038 - - 24,170.73 - - 60,469.89 - - 13,278 - - 11,876.49 - - 29,741.49 - - 13,760 - - 12,294.24 - - 30,728.40 -
      - Periodicals - - All Marital Status - - 4,294 - - 3,614.55 - - 9,056.76 - - 2,168 - - 1,833.48 - - 4,583.08 - - 2,126 - - 1,781.08 - - 4,473.68 -
      +   + + Gender +
      + All Gender + + F + + M +
      + Measures + + Measures + + Measures +
      + Promotion Media + + Product + + Marital Status + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + All Products + + All Marital Status + + 266,773 + + 225,627.23 + + 565,238.13 + + 131,558 + + 111,777.48 + + 280,226.21 + + 135,215 + + 113,849.75 + + 285,011.92 +
      + Drink + + All Marital Status + + 24,597 + + 19,477.23 + + 48,836.21 + + 12,202 + + 9,751.10 + + 24,457.37 + + 12,395 + + 9,726.14 + + 24,378.84 +
      + Food + + All Marital Status + + 191,940 + + 163,270.72 + + 409,035.59 + + 94,814 + + 80,993.45 + + 203,094.17 + + 97,126 + + 82,277.27 + + 205,941.42 +
      + Baked Goods + + All Marital Status + + 7,870 + + 6,564.09 + + 16,455.43 + + 3,771 + + 3,164.76 + + 7,938.38 + + 4,099 + + 3,399.34 + + 8,517.05 +
      + Baking Goods + + All Marital Status + + 20,245 + + 15,370.61 + + 38,670.41 + + 9,841 + + 7,389.74 + + 18,608.22 + + 10,404 + + 7,980.87 + + 20,062.19 +
      + Baking Goods + + All Marital Status + + 8,357 + + 6,123.32 + + 15,446.69 + + 4,005 + + 2,907.70 + + 7,313.61 + + 4,352 + + 3,215.62 + + 8,133.08 +
      + M + + 4,167 + + 3,044.62 + + 7,656.25 + + 2,028 + + 1,469.66 + + 3,711.91 + + 2,139 + + 1,574.96 + + 3,944.34 +
      + S + + 4,190 + + 3,078.70 + + 7,790.44 + + 1,977 + + 1,438.04 + + 3,601.70 + + 2,213 + + 1,640.66 + + 4,188.74 +
      + Jams and Jellies + + All Marital Status + + 11,888 + + 9,247.29 + + 23,223.72 + + 5,836 + + 4,482.04 + + 11,294.61 + + 6,052 + + 4,765.25 + + 11,929.11 +
      + Breakfast Foods + + All Marital Status + + 3,317 + + 2,756.80 + + 6,941.46 + + 1,821 + + 1,522.93 + + 3,840.30 + + 1,496 + + 1,233.87 + + 3,101.16 +
      + Canned Foods + + All Marital Status + + 19,026 + + 15,894.53 + + 39,774.34 + + 9,407 + + 7,942.57 + + 19,864.15 + + 9,619 + + 7,951.97 + + 19,910.19 +
      + Canned Products + + All Marital Status + + 1,812 + + 1,317.13 + + 3,314.52 + + 867 + + 613.76 + + 1,551.30 + + 945 + + 703.37 + + 1,763.22 +
      + Dairy + + All Marital Status + + 12,885 + + 12,228.85 + + 30,508.85 + + 6,513 + + 6,253.73 + + 15,603.84 + + 6,372 + + 5,975.12 + + 14,905.01 +
      + Deli + + All Marital Status + + 12,037 + + 10,108.87 + + 25,318.93 + + 5,990 + + 5,022.05 + + 12,592.39 + + 6,047 + + 5,086.82 + + 12,726.54 +
      + Eggs + + All Marital Status + + 4,132 + + 3,684.90 + + 9,200.76 + + 2,001 + + 1,746.06 + + 4,355.68 + + 2,131 + + 1,938.84 + + 4,845.08 +
      + Frozen Foods + + All Marital Status + + 26,655 + + 22,030.66 + + 55,207.50 + + 13,011 + + 10,843.01 + + 27,168.52 + + 13,644 + + 11,187.65 + + 28,038.98 +
      + Meat + + All Marital Status + + 1,714 + + 1,465.42 + + 3,669.89 + + 841 + + 716.84 + + 1,797.60 + + 873 + + 748.59 + + 1,872.29 +
      + Produce + + All Marital Status + + 37,792 + + 32,831.33 + + 82,248.42 + + 18,713 + + 16,403.72 + + 41,069.39 + + 19,079 + + 16,427.61 + + 41,179.03 +
      + Seafood + + All Marital Status + + 1,764 + + 1,520.70 + + 3,809.14 + + 947 + + 836.19 + + 2,095.55 + + 817 + + 684.51 + + 1,713.59 +
      + Snack Foods + + All Marital Status + + 30,545 + + 26,963.34 + + 67,609.82 + + 14,936 + + 13,160.27 + + 33,120.45 + + 15,609 + + 13,803.07 + + 34,489.37 +
      + Snacks + + All Marital Status + + 6,884 + + 5,827.58 + + 14,550.05 + + 3,459 + + 2,960.73 + + 7,430.30 + + 3,425 + + 2,866.86 + + 7,119.75 +
      + Starchy Foods + + All Marital Status + + 5,262 + + 4,705.91 + + 11,756.07 + + 2,696 + + 2,417.11 + + 6,058.10 + + 2,566 + + 2,288.79 + + 5,697.97 +
      + Non-Consumable + + All Marital Status + + 50,236 + + 42,879.28 + + 107,366.33 + + 24,542 + + 21,032.93 + + 52,674.67 + + 25,694 + + 21,846.35 + + 54,691.66 +
      + Carousel + + All Marital Status + + 841 + + 595.97 + + 1,500.11 + + 368 + + 258.40 + + 655.55 + + 473 + + 337.57 + + 844.56 +
      + Checkout + + All Marital Status + + 1,779 + + 1,525.04 + + 3,767.71 + + 887 + + 755.83 + + 1,874.82 + + 892 + + 769.21 + + 1,892.89 +
      + Health and Hygiene + + All Marital Status + + 16,284 + + 12,972.99 + + 32,571.86 + + 7,841 + + 6,308.73 + + 15,819.73 + + 8,443 + + 6,664.25 + + 16,752.13 +
      + Household + + All Marital Status + + 27,038 + + 24,170.73 + + 60,469.89 + + 13,278 + + 11,876.49 + + 29,741.49 + + 13,760 + + 12,294.24 + + 30,728.40 +
      + Periodicals + + All Marital Status + + 4,294 + + 3,614.55 + + 9,056.76 + + 2,168 + + 1,833.48 + + 4,583.08 + + 2,126 + + 1,781.08 + + 4,473.68 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/basic-false-true-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/basic-false-true-true-result.html index 7416a525..32c799bf 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/basic-false-true-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/basic-false-true-true-result.html @@ -1,1092 +1,1092 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Gender -
      - All Gender - - All Gender -
      - F - - M -
      - Promotion Media - - Product - - Marital Status - - Measures - - Measures - - Measures -
      - (All) - - (All) - - Product Family - - Product Department - - Product Category - - (All) - - Marital Status - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - All Products - - All Marital Status - - 266,773 - - 225,627.23 - - 565,238.13 - - 131,558 - - 111,777.48 - - 280,226.21 - - 135,215 - - 113,849.75 - - 285,011.92 -
      - All Products - - Drink - - All Marital Status - - 24,597 - - 19,477.23 - - 48,836.21 - - 12,202 - - 9,751.10 - - 24,457.37 - - 12,395 - - 9,726.14 - - 24,378.84 -
      - Food - - All Marital Status - - 191,940 - - 163,270.72 - - 409,035.59 - - 94,814 - - 80,993.45 - - 203,094.17 - - 97,126 - - 82,277.27 - - 205,941.42 -
      - Food - - Baked Goods - - All Marital Status - - 7,870 - - 6,564.09 - - 16,455.43 - - 3,771 - - 3,164.76 - - 7,938.38 - - 4,099 - - 3,399.34 - - 8,517.05 -
      - Baking Goods - - All Marital Status - - 20,245 - - 15,370.61 - - 38,670.41 - - 9,841 - - 7,389.74 - - 18,608.22 - - 10,404 - - 7,980.87 - - 20,062.19 -
      - Baking Goods - - Baking Goods - - All Marital Status - - 8,357 - - 6,123.32 - - 15,446.69 - - 4,005 - - 2,907.70 - - 7,313.61 - - 4,352 - - 3,215.62 - - 8,133.08 -
      - All Marital Status - - M - - 4,167 - - 3,044.62 - - 7,656.25 - - 2,028 - - 1,469.66 - - 3,711.91 - - 2,139 - - 1,574.96 - - 3,944.34 -
      - S - - 4,190 - - 3,078.70 - - 7,790.44 - - 1,977 - - 1,438.04 - - 3,601.70 - - 2,213 - - 1,640.66 - - 4,188.74 -
      - Jams and Jellies - - All Marital Status - - 11,888 - - 9,247.29 - - 23,223.72 - - 5,836 - - 4,482.04 - - 11,294.61 - - 6,052 - - 4,765.25 - - 11,929.11 -
      - Breakfast Foods - - All Marital Status - - 3,317 - - 2,756.80 - - 6,941.46 - - 1,821 - - 1,522.93 - - 3,840.30 - - 1,496 - - 1,233.87 - - 3,101.16 -
      - Canned Foods - - All Marital Status - - 19,026 - - 15,894.53 - - 39,774.34 - - 9,407 - - 7,942.57 - - 19,864.15 - - 9,619 - - 7,951.97 - - 19,910.19 -
      - Canned Products - - All Marital Status - - 1,812 - - 1,317.13 - - 3,314.52 - - 867 - - 613.76 - - 1,551.30 - - 945 - - 703.37 - - 1,763.22 -
      - Dairy - - All Marital Status - - 12,885 - - 12,228.85 - - 30,508.85 - - 6,513 - - 6,253.73 - - 15,603.84 - - 6,372 - - 5,975.12 - - 14,905.01 -
      - Deli - - All Marital Status - - 12,037 - - 10,108.87 - - 25,318.93 - - 5,990 - - 5,022.05 - - 12,592.39 - - 6,047 - - 5,086.82 - - 12,726.54 -
      - Eggs - - All Marital Status - - 4,132 - - 3,684.90 - - 9,200.76 - - 2,001 - - 1,746.06 - - 4,355.68 - - 2,131 - - 1,938.84 - - 4,845.08 -
      - Frozen Foods - - All Marital Status - - 26,655 - - 22,030.66 - - 55,207.50 - - 13,011 - - 10,843.01 - - 27,168.52 - - 13,644 - - 11,187.65 - - 28,038.98 -
      - Meat - - All Marital Status - - 1,714 - - 1,465.42 - - 3,669.89 - - 841 - - 716.84 - - 1,797.60 - - 873 - - 748.59 - - 1,872.29 -
      - Produce - - All Marital Status - - 37,792 - - 32,831.33 - - 82,248.42 - - 18,713 - - 16,403.72 - - 41,069.39 - - 19,079 - - 16,427.61 - - 41,179.03 -
      - Seafood - - All Marital Status - - 1,764 - - 1,520.70 - - 3,809.14 - - 947 - - 836.19 - - 2,095.55 - - 817 - - 684.51 - - 1,713.59 -
      - Snack Foods - - All Marital Status - - 30,545 - - 26,963.34 - - 67,609.82 - - 14,936 - - 13,160.27 - - 33,120.45 - - 15,609 - - 13,803.07 - - 34,489.37 -
      - Snacks - - All Marital Status - - 6,884 - - 5,827.58 - - 14,550.05 - - 3,459 - - 2,960.73 - - 7,430.30 - - 3,425 - - 2,866.86 - - 7,119.75 -
      - Starchy Foods - - All Marital Status - - 5,262 - - 4,705.91 - - 11,756.07 - - 2,696 - - 2,417.11 - - 6,058.10 - - 2,566 - - 2,288.79 - - 5,697.97 -
      - Non-Consumable - - All Marital Status - - 50,236 - - 42,879.28 - - 107,366.33 - - 24,542 - - 21,032.93 - - 52,674.67 - - 25,694 - - 21,846.35 - - 54,691.66 -
      - Non-Consumable - - Carousel - - All Marital Status - - 841 - - 595.97 - - 1,500.11 - - 368 - - 258.40 - - 655.55 - - 473 - - 337.57 - - 844.56 -
      - Checkout - - All Marital Status - - 1,779 - - 1,525.04 - - 3,767.71 - - 887 - - 755.83 - - 1,874.82 - - 892 - - 769.21 - - 1,892.89 -
      - Health and Hygiene - - All Marital Status - - 16,284 - - 12,972.99 - - 32,571.86 - - 7,841 - - 6,308.73 - - 15,819.73 - - 8,443 - - 6,664.25 - - 16,752.13 -
      - Household - - All Marital Status - - 27,038 - - 24,170.73 - - 60,469.89 - - 13,278 - - 11,876.49 - - 29,741.49 - - 13,760 - - 12,294.24 - - 30,728.40 -
      - Periodicals - - All Marital Status - - 4,294 - - 3,614.55 - - 9,056.76 - - 2,168 - - 1,833.48 - - 4,583.08 - - 2,126 - - 1,781.08 - - 4,473.68 -
      +   + + Gender +
      + All Gender + + All Gender +
      + F + + M +
      + Promotion Media + + Product + + Marital Status + + Measures + + Measures + + Measures +
      + (All) + + (All) + + Product Family + + Product Department + + Product Category + + (All) + + Marital Status + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + All Products + + All Marital Status + + 266,773 + + 225,627.23 + + 565,238.13 + + 131,558 + + 111,777.48 + + 280,226.21 + + 135,215 + + 113,849.75 + + 285,011.92 +
      + All Products + + Drink + + All Marital Status + + 24,597 + + 19,477.23 + + 48,836.21 + + 12,202 + + 9,751.10 + + 24,457.37 + + 12,395 + + 9,726.14 + + 24,378.84 +
      + Food + + All Marital Status + + 191,940 + + 163,270.72 + + 409,035.59 + + 94,814 + + 80,993.45 + + 203,094.17 + + 97,126 + + 82,277.27 + + 205,941.42 +
      + Food + + Baked Goods + + All Marital Status + + 7,870 + + 6,564.09 + + 16,455.43 + + 3,771 + + 3,164.76 + + 7,938.38 + + 4,099 + + 3,399.34 + + 8,517.05 +
      + Baking Goods + + All Marital Status + + 20,245 + + 15,370.61 + + 38,670.41 + + 9,841 + + 7,389.74 + + 18,608.22 + + 10,404 + + 7,980.87 + + 20,062.19 +
      + Baking Goods + + Baking Goods + + All Marital Status + + 8,357 + + 6,123.32 + + 15,446.69 + + 4,005 + + 2,907.70 + + 7,313.61 + + 4,352 + + 3,215.62 + + 8,133.08 +
      + All Marital Status + + M + + 4,167 + + 3,044.62 + + 7,656.25 + + 2,028 + + 1,469.66 + + 3,711.91 + + 2,139 + + 1,574.96 + + 3,944.34 +
      + S + + 4,190 + + 3,078.70 + + 7,790.44 + + 1,977 + + 1,438.04 + + 3,601.70 + + 2,213 + + 1,640.66 + + 4,188.74 +
      + Jams and Jellies + + All Marital Status + + 11,888 + + 9,247.29 + + 23,223.72 + + 5,836 + + 4,482.04 + + 11,294.61 + + 6,052 + + 4,765.25 + + 11,929.11 +
      + Breakfast Foods + + All Marital Status + + 3,317 + + 2,756.80 + + 6,941.46 + + 1,821 + + 1,522.93 + + 3,840.30 + + 1,496 + + 1,233.87 + + 3,101.16 +
      + Canned Foods + + All Marital Status + + 19,026 + + 15,894.53 + + 39,774.34 + + 9,407 + + 7,942.57 + + 19,864.15 + + 9,619 + + 7,951.97 + + 19,910.19 +
      + Canned Products + + All Marital Status + + 1,812 + + 1,317.13 + + 3,314.52 + + 867 + + 613.76 + + 1,551.30 + + 945 + + 703.37 + + 1,763.22 +
      + Dairy + + All Marital Status + + 12,885 + + 12,228.85 + + 30,508.85 + + 6,513 + + 6,253.73 + + 15,603.84 + + 6,372 + + 5,975.12 + + 14,905.01 +
      + Deli + + All Marital Status + + 12,037 + + 10,108.87 + + 25,318.93 + + 5,990 + + 5,022.05 + + 12,592.39 + + 6,047 + + 5,086.82 + + 12,726.54 +
      + Eggs + + All Marital Status + + 4,132 + + 3,684.90 + + 9,200.76 + + 2,001 + + 1,746.06 + + 4,355.68 + + 2,131 + + 1,938.84 + + 4,845.08 +
      + Frozen Foods + + All Marital Status + + 26,655 + + 22,030.66 + + 55,207.50 + + 13,011 + + 10,843.01 + + 27,168.52 + + 13,644 + + 11,187.65 + + 28,038.98 +
      + Meat + + All Marital Status + + 1,714 + + 1,465.42 + + 3,669.89 + + 841 + + 716.84 + + 1,797.60 + + 873 + + 748.59 + + 1,872.29 +
      + Produce + + All Marital Status + + 37,792 + + 32,831.33 + + 82,248.42 + + 18,713 + + 16,403.72 + + 41,069.39 + + 19,079 + + 16,427.61 + + 41,179.03 +
      + Seafood + + All Marital Status + + 1,764 + + 1,520.70 + + 3,809.14 + + 947 + + 836.19 + + 2,095.55 + + 817 + + 684.51 + + 1,713.59 +
      + Snack Foods + + All Marital Status + + 30,545 + + 26,963.34 + + 67,609.82 + + 14,936 + + 13,160.27 + + 33,120.45 + + 15,609 + + 13,803.07 + + 34,489.37 +
      + Snacks + + All Marital Status + + 6,884 + + 5,827.58 + + 14,550.05 + + 3,459 + + 2,960.73 + + 7,430.30 + + 3,425 + + 2,866.86 + + 7,119.75 +
      + Starchy Foods + + All Marital Status + + 5,262 + + 4,705.91 + + 11,756.07 + + 2,696 + + 2,417.11 + + 6,058.10 + + 2,566 + + 2,288.79 + + 5,697.97 +
      + Non-Consumable + + All Marital Status + + 50,236 + + 42,879.28 + + 107,366.33 + + 24,542 + + 21,032.93 + + 52,674.67 + + 25,694 + + 21,846.35 + + 54,691.66 +
      + Non-Consumable + + Carousel + + All Marital Status + + 841 + + 595.97 + + 1,500.11 + + 368 + + 258.40 + + 655.55 + + 473 + + 337.57 + + 844.56 +
      + Checkout + + All Marital Status + + 1,779 + + 1,525.04 + + 3,767.71 + + 887 + + 755.83 + + 1,874.82 + + 892 + + 769.21 + + 1,892.89 +
      + Health and Hygiene + + All Marital Status + + 16,284 + + 12,972.99 + + 32,571.86 + + 7,841 + + 6,308.73 + + 15,819.73 + + 8,443 + + 6,664.25 + + 16,752.13 +
      + Household + + All Marital Status + + 27,038 + + 24,170.73 + + 60,469.89 + + 13,278 + + 11,876.49 + + 29,741.49 + + 13,760 + + 12,294.24 + + 30,728.40 +
      + Periodicals + + All Marital Status + + 4,294 + + 3,614.55 + + 9,056.76 + + 2,168 + + 1,833.48 + + 4,583.08 + + 2,126 + + 1,781.08 + + 4,473.68 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/basic-true-false-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/basic-true-false-false-result.html index 66ffe86b..eed20a9f 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/basic-true-false-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/basic-true-false-false-result.html @@ -1,1131 +1,1131 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - All Gender - - All Gender - - All Gender - - F - - F - - F - - M - - M - - M -
      - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - All Products - - All Marital Status - - 266,773 - - 225,627.23 - - 565,238.13 - - 131,558 - - 111,777.48 - - 280,226.21 - - 135,215 - - 113,849.75 - - 285,011.92 -
      - All Media - - Drink - - All Marital Status - - 24,597 - - 19,477.23 - - 48,836.21 - - 12,202 - - 9,751.10 - - 24,457.37 - - 12,395 - - 9,726.14 - - 24,378.84 -
      - All Media - - Food - - All Marital Status - - 191,940 - - 163,270.72 - - 409,035.59 - - 94,814 - - 80,993.45 - - 203,094.17 - - 97,126 - - 82,277.27 - - 205,941.42 -
      - All Media - - Baked Goods - - All Marital Status - - 7,870 - - 6,564.09 - - 16,455.43 - - 3,771 - - 3,164.76 - - 7,938.38 - - 4,099 - - 3,399.34 - - 8,517.05 -
      - All Media - - Baking Goods - - All Marital Status - - 20,245 - - 15,370.61 - - 38,670.41 - - 9,841 - - 7,389.74 - - 18,608.22 - - 10,404 - - 7,980.87 - - 20,062.19 -
      - All Media - - Baking Goods - - All Marital Status - - 8,357 - - 6,123.32 - - 15,446.69 - - 4,005 - - 2,907.70 - - 7,313.61 - - 4,352 - - 3,215.62 - - 8,133.08 -
      - All Media - - Baking Goods - - M - - 4,167 - - 3,044.62 - - 7,656.25 - - 2,028 - - 1,469.66 - - 3,711.91 - - 2,139 - - 1,574.96 - - 3,944.34 -
      - All Media - - Baking Goods - - S - - 4,190 - - 3,078.70 - - 7,790.44 - - 1,977 - - 1,438.04 - - 3,601.70 - - 2,213 - - 1,640.66 - - 4,188.74 -
      - All Media - - Jams and Jellies - - All Marital Status - - 11,888 - - 9,247.29 - - 23,223.72 - - 5,836 - - 4,482.04 - - 11,294.61 - - 6,052 - - 4,765.25 - - 11,929.11 -
      - All Media - - Breakfast Foods - - All Marital Status - - 3,317 - - 2,756.80 - - 6,941.46 - - 1,821 - - 1,522.93 - - 3,840.30 - - 1,496 - - 1,233.87 - - 3,101.16 -
      - All Media - - Canned Foods - - All Marital Status - - 19,026 - - 15,894.53 - - 39,774.34 - - 9,407 - - 7,942.57 - - 19,864.15 - - 9,619 - - 7,951.97 - - 19,910.19 -
      - All Media - - Canned Products - - All Marital Status - - 1,812 - - 1,317.13 - - 3,314.52 - - 867 - - 613.76 - - 1,551.30 - - 945 - - 703.37 - - 1,763.22 -
      - All Media - - Dairy - - All Marital Status - - 12,885 - - 12,228.85 - - 30,508.85 - - 6,513 - - 6,253.73 - - 15,603.84 - - 6,372 - - 5,975.12 - - 14,905.01 -
      - All Media - - Deli - - All Marital Status - - 12,037 - - 10,108.87 - - 25,318.93 - - 5,990 - - 5,022.05 - - 12,592.39 - - 6,047 - - 5,086.82 - - 12,726.54 -
      - All Media - - Eggs - - All Marital Status - - 4,132 - - 3,684.90 - - 9,200.76 - - 2,001 - - 1,746.06 - - 4,355.68 - - 2,131 - - 1,938.84 - - 4,845.08 -
      - All Media - - Frozen Foods - - All Marital Status - - 26,655 - - 22,030.66 - - 55,207.50 - - 13,011 - - 10,843.01 - - 27,168.52 - - 13,644 - - 11,187.65 - - 28,038.98 -
      - All Media - - Meat - - All Marital Status - - 1,714 - - 1,465.42 - - 3,669.89 - - 841 - - 716.84 - - 1,797.60 - - 873 - - 748.59 - - 1,872.29 -
      - All Media - - Produce - - All Marital Status - - 37,792 - - 32,831.33 - - 82,248.42 - - 18,713 - - 16,403.72 - - 41,069.39 - - 19,079 - - 16,427.61 - - 41,179.03 -
      - All Media - - Seafood - - All Marital Status - - 1,764 - - 1,520.70 - - 3,809.14 - - 947 - - 836.19 - - 2,095.55 - - 817 - - 684.51 - - 1,713.59 -
      - All Media - - Snack Foods - - All Marital Status - - 30,545 - - 26,963.34 - - 67,609.82 - - 14,936 - - 13,160.27 - - 33,120.45 - - 15,609 - - 13,803.07 - - 34,489.37 -
      - All Media - - Snacks - - All Marital Status - - 6,884 - - 5,827.58 - - 14,550.05 - - 3,459 - - 2,960.73 - - 7,430.30 - - 3,425 - - 2,866.86 - - 7,119.75 -
      - All Media - - Starchy Foods - - All Marital Status - - 5,262 - - 4,705.91 - - 11,756.07 - - 2,696 - - 2,417.11 - - 6,058.10 - - 2,566 - - 2,288.79 - - 5,697.97 -
      - All Media - - Non-Consumable - - All Marital Status - - 50,236 - - 42,879.28 - - 107,366.33 - - 24,542 - - 21,032.93 - - 52,674.67 - - 25,694 - - 21,846.35 - - 54,691.66 -
      - All Media - - Carousel - - All Marital Status - - 841 - - 595.97 - - 1,500.11 - - 368 - - 258.40 - - 655.55 - - 473 - - 337.57 - - 844.56 -
      - All Media - - Checkout - - All Marital Status - - 1,779 - - 1,525.04 - - 3,767.71 - - 887 - - 755.83 - - 1,874.82 - - 892 - - 769.21 - - 1,892.89 -
      - All Media - - Health and Hygiene - - All Marital Status - - 16,284 - - 12,972.99 - - 32,571.86 - - 7,841 - - 6,308.73 - - 15,819.73 - - 8,443 - - 6,664.25 - - 16,752.13 -
      - All Media - - Household - - All Marital Status - - 27,038 - - 24,170.73 - - 60,469.89 - - 13,278 - - 11,876.49 - - 29,741.49 - - 13,760 - - 12,294.24 - - 30,728.40 -
      - All Media - - Periodicals - - All Marital Status - - 4,294 - - 3,614.55 - - 9,056.76 - - 2,168 - - 1,833.48 - - 4,583.08 - - 2,126 - - 1,781.08 - - 4,473.68 -
      +   + + All Gender + + All Gender + + All Gender + + F + + F + + F + + M + + M + + M +
      + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + All Products + + All Marital Status + + 266,773 + + 225,627.23 + + 565,238.13 + + 131,558 + + 111,777.48 + + 280,226.21 + + 135,215 + + 113,849.75 + + 285,011.92 +
      + All Media + + Drink + + All Marital Status + + 24,597 + + 19,477.23 + + 48,836.21 + + 12,202 + + 9,751.10 + + 24,457.37 + + 12,395 + + 9,726.14 + + 24,378.84 +
      + All Media + + Food + + All Marital Status + + 191,940 + + 163,270.72 + + 409,035.59 + + 94,814 + + 80,993.45 + + 203,094.17 + + 97,126 + + 82,277.27 + + 205,941.42 +
      + All Media + + Baked Goods + + All Marital Status + + 7,870 + + 6,564.09 + + 16,455.43 + + 3,771 + + 3,164.76 + + 7,938.38 + + 4,099 + + 3,399.34 + + 8,517.05 +
      + All Media + + Baking Goods + + All Marital Status + + 20,245 + + 15,370.61 + + 38,670.41 + + 9,841 + + 7,389.74 + + 18,608.22 + + 10,404 + + 7,980.87 + + 20,062.19 +
      + All Media + + Baking Goods + + All Marital Status + + 8,357 + + 6,123.32 + + 15,446.69 + + 4,005 + + 2,907.70 + + 7,313.61 + + 4,352 + + 3,215.62 + + 8,133.08 +
      + All Media + + Baking Goods + + M + + 4,167 + + 3,044.62 + + 7,656.25 + + 2,028 + + 1,469.66 + + 3,711.91 + + 2,139 + + 1,574.96 + + 3,944.34 +
      + All Media + + Baking Goods + + S + + 4,190 + + 3,078.70 + + 7,790.44 + + 1,977 + + 1,438.04 + + 3,601.70 + + 2,213 + + 1,640.66 + + 4,188.74 +
      + All Media + + Jams and Jellies + + All Marital Status + + 11,888 + + 9,247.29 + + 23,223.72 + + 5,836 + + 4,482.04 + + 11,294.61 + + 6,052 + + 4,765.25 + + 11,929.11 +
      + All Media + + Breakfast Foods + + All Marital Status + + 3,317 + + 2,756.80 + + 6,941.46 + + 1,821 + + 1,522.93 + + 3,840.30 + + 1,496 + + 1,233.87 + + 3,101.16 +
      + All Media + + Canned Foods + + All Marital Status + + 19,026 + + 15,894.53 + + 39,774.34 + + 9,407 + + 7,942.57 + + 19,864.15 + + 9,619 + + 7,951.97 + + 19,910.19 +
      + All Media + + Canned Products + + All Marital Status + + 1,812 + + 1,317.13 + + 3,314.52 + + 867 + + 613.76 + + 1,551.30 + + 945 + + 703.37 + + 1,763.22 +
      + All Media + + Dairy + + All Marital Status + + 12,885 + + 12,228.85 + + 30,508.85 + + 6,513 + + 6,253.73 + + 15,603.84 + + 6,372 + + 5,975.12 + + 14,905.01 +
      + All Media + + Deli + + All Marital Status + + 12,037 + + 10,108.87 + + 25,318.93 + + 5,990 + + 5,022.05 + + 12,592.39 + + 6,047 + + 5,086.82 + + 12,726.54 +
      + All Media + + Eggs + + All Marital Status + + 4,132 + + 3,684.90 + + 9,200.76 + + 2,001 + + 1,746.06 + + 4,355.68 + + 2,131 + + 1,938.84 + + 4,845.08 +
      + All Media + + Frozen Foods + + All Marital Status + + 26,655 + + 22,030.66 + + 55,207.50 + + 13,011 + + 10,843.01 + + 27,168.52 + + 13,644 + + 11,187.65 + + 28,038.98 +
      + All Media + + Meat + + All Marital Status + + 1,714 + + 1,465.42 + + 3,669.89 + + 841 + + 716.84 + + 1,797.60 + + 873 + + 748.59 + + 1,872.29 +
      + All Media + + Produce + + All Marital Status + + 37,792 + + 32,831.33 + + 82,248.42 + + 18,713 + + 16,403.72 + + 41,069.39 + + 19,079 + + 16,427.61 + + 41,179.03 +
      + All Media + + Seafood + + All Marital Status + + 1,764 + + 1,520.70 + + 3,809.14 + + 947 + + 836.19 + + 2,095.55 + + 817 + + 684.51 + + 1,713.59 +
      + All Media + + Snack Foods + + All Marital Status + + 30,545 + + 26,963.34 + + 67,609.82 + + 14,936 + + 13,160.27 + + 33,120.45 + + 15,609 + + 13,803.07 + + 34,489.37 +
      + All Media + + Snacks + + All Marital Status + + 6,884 + + 5,827.58 + + 14,550.05 + + 3,459 + + 2,960.73 + + 7,430.30 + + 3,425 + + 2,866.86 + + 7,119.75 +
      + All Media + + Starchy Foods + + All Marital Status + + 5,262 + + 4,705.91 + + 11,756.07 + + 2,696 + + 2,417.11 + + 6,058.10 + + 2,566 + + 2,288.79 + + 5,697.97 +
      + All Media + + Non-Consumable + + All Marital Status + + 50,236 + + 42,879.28 + + 107,366.33 + + 24,542 + + 21,032.93 + + 52,674.67 + + 25,694 + + 21,846.35 + + 54,691.66 +
      + All Media + + Carousel + + All Marital Status + + 841 + + 595.97 + + 1,500.11 + + 368 + + 258.40 + + 655.55 + + 473 + + 337.57 + + 844.56 +
      + All Media + + Checkout + + All Marital Status + + 1,779 + + 1,525.04 + + 3,767.71 + + 887 + + 755.83 + + 1,874.82 + + 892 + + 769.21 + + 1,892.89 +
      + All Media + + Health and Hygiene + + All Marital Status + + 16,284 + + 12,972.99 + + 32,571.86 + + 7,841 + + 6,308.73 + + 15,819.73 + + 8,443 + + 6,664.25 + + 16,752.13 +
      + All Media + + Household + + All Marital Status + + 27,038 + + 24,170.73 + + 60,469.89 + + 13,278 + + 11,876.49 + + 29,741.49 + + 13,760 + + 12,294.24 + + 30,728.40 +
      + All Media + + Periodicals + + All Marital Status + + 4,294 + + 3,614.55 + + 9,056.76 + + 2,168 + + 1,833.48 + + 4,583.08 + + 2,126 + + 1,781.08 + + 4,473.68 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/basic-true-false-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/basic-true-false-true-result.html index 67874975..82b1f0c4 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/basic-true-false-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/basic-true-false-true-result.html @@ -1,1322 +1,1322 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender -
      - F - - F - - F - - M - - M - - M -
      - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - All Products - - All Marital Status - - 266,773 - - 225,627.23 - - 565,238.13 - - 131,558 - - 111,777.48 - - 280,226.21 - - 135,215 - - 113,849.75 - - 285,011.92 -
      - All Media - - All Products - - Drink - - All Marital Status - - 24,597 - - 19,477.23 - - 48,836.21 - - 12,202 - - 9,751.10 - - 24,457.37 - - 12,395 - - 9,726.14 - - 24,378.84 -
      - All Media - - All Products - - Food - - All Marital Status - - 191,940 - - 163,270.72 - - 409,035.59 - - 94,814 - - 80,993.45 - - 203,094.17 - - 97,126 - - 82,277.27 - - 205,941.42 -
      - All Media - - All Products - - Food - - Baked Goods - - All Marital Status - - 7,870 - - 6,564.09 - - 16,455.43 - - 3,771 - - 3,164.76 - - 7,938.38 - - 4,099 - - 3,399.34 - - 8,517.05 -
      - All Media - - All Products - - Food - - Baking Goods - - All Marital Status - - 20,245 - - 15,370.61 - - 38,670.41 - - 9,841 - - 7,389.74 - - 18,608.22 - - 10,404 - - 7,980.87 - - 20,062.19 -
      - All Media - - All Products - - Food - - Baking Goods - - Baking Goods - - All Marital Status - - 8,357 - - 6,123.32 - - 15,446.69 - - 4,005 - - 2,907.70 - - 7,313.61 - - 4,352 - - 3,215.62 - - 8,133.08 -
      - All Media - - All Products - - Food - - Baking Goods - - Baking Goods - - All Marital Status - - M - - 4,167 - - 3,044.62 - - 7,656.25 - - 2,028 - - 1,469.66 - - 3,711.91 - - 2,139 - - 1,574.96 - - 3,944.34 -
      - All Media - - All Products - - Food - - Baking Goods - - Baking Goods - - All Marital Status - - S - - 4,190 - - 3,078.70 - - 7,790.44 - - 1,977 - - 1,438.04 - - 3,601.70 - - 2,213 - - 1,640.66 - - 4,188.74 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - All Marital Status - - 11,888 - - 9,247.29 - - 23,223.72 - - 5,836 - - 4,482.04 - - 11,294.61 - - 6,052 - - 4,765.25 - - 11,929.11 -
      - All Media - - All Products - - Food - - Breakfast Foods - - All Marital Status - - 3,317 - - 2,756.80 - - 6,941.46 - - 1,821 - - 1,522.93 - - 3,840.30 - - 1,496 - - 1,233.87 - - 3,101.16 -
      - All Media - - All Products - - Food - - Canned Foods - - All Marital Status - - 19,026 - - 15,894.53 - - 39,774.34 - - 9,407 - - 7,942.57 - - 19,864.15 - - 9,619 - - 7,951.97 - - 19,910.19 -
      - All Media - - All Products - - Food - - Canned Products - - All Marital Status - - 1,812 - - 1,317.13 - - 3,314.52 - - 867 - - 613.76 - - 1,551.30 - - 945 - - 703.37 - - 1,763.22 -
      - All Media - - All Products - - Food - - Dairy - - All Marital Status - - 12,885 - - 12,228.85 - - 30,508.85 - - 6,513 - - 6,253.73 - - 15,603.84 - - 6,372 - - 5,975.12 - - 14,905.01 -
      - All Media - - All Products - - Food - - Deli - - All Marital Status - - 12,037 - - 10,108.87 - - 25,318.93 - - 5,990 - - 5,022.05 - - 12,592.39 - - 6,047 - - 5,086.82 - - 12,726.54 -
      - All Media - - All Products - - Food - - Eggs - - All Marital Status - - 4,132 - - 3,684.90 - - 9,200.76 - - 2,001 - - 1,746.06 - - 4,355.68 - - 2,131 - - 1,938.84 - - 4,845.08 -
      - All Media - - All Products - - Food - - Frozen Foods - - All Marital Status - - 26,655 - - 22,030.66 - - 55,207.50 - - 13,011 - - 10,843.01 - - 27,168.52 - - 13,644 - - 11,187.65 - - 28,038.98 -
      - All Media - - All Products - - Food - - Meat - - All Marital Status - - 1,714 - - 1,465.42 - - 3,669.89 - - 841 - - 716.84 - - 1,797.60 - - 873 - - 748.59 - - 1,872.29 -
      - All Media - - All Products - - Food - - Produce - - All Marital Status - - 37,792 - - 32,831.33 - - 82,248.42 - - 18,713 - - 16,403.72 - - 41,069.39 - - 19,079 - - 16,427.61 - - 41,179.03 -
      - All Media - - All Products - - Food - - Seafood - - All Marital Status - - 1,764 - - 1,520.70 - - 3,809.14 - - 947 - - 836.19 - - 2,095.55 - - 817 - - 684.51 - - 1,713.59 -
      - All Media - - All Products - - Food - - Snack Foods - - All Marital Status - - 30,545 - - 26,963.34 - - 67,609.82 - - 14,936 - - 13,160.27 - - 33,120.45 - - 15,609 - - 13,803.07 - - 34,489.37 -
      - All Media - - All Products - - Food - - Snacks - - All Marital Status - - 6,884 - - 5,827.58 - - 14,550.05 - - 3,459 - - 2,960.73 - - 7,430.30 - - 3,425 - - 2,866.86 - - 7,119.75 -
      - All Media - - All Products - - Food - - Starchy Foods - - All Marital Status - - 5,262 - - 4,705.91 - - 11,756.07 - - 2,696 - - 2,417.11 - - 6,058.10 - - 2,566 - - 2,288.79 - - 5,697.97 -
      - All Media - - All Products - - Non-Consumable - - All Marital Status - - 50,236 - - 42,879.28 - - 107,366.33 - - 24,542 - - 21,032.93 - - 52,674.67 - - 25,694 - - 21,846.35 - - 54,691.66 -
      - All Media - - All Products - - Non-Consumable - - Carousel - - All Marital Status - - 841 - - 595.97 - - 1,500.11 - - 368 - - 258.40 - - 655.55 - - 473 - - 337.57 - - 844.56 -
      - All Media - - All Products - - Non-Consumable - - Checkout - - All Marital Status - - 1,779 - - 1,525.04 - - 3,767.71 - - 887 - - 755.83 - - 1,874.82 - - 892 - - 769.21 - - 1,892.89 -
      - All Media - - All Products - - Non-Consumable - - Health and Hygiene - - All Marital Status - - 16,284 - - 12,972.99 - - 32,571.86 - - 7,841 - - 6,308.73 - - 15,819.73 - - 8,443 - - 6,664.25 - - 16,752.13 -
      - All Media - - All Products - - Non-Consumable - - Household - - All Marital Status - - 27,038 - - 24,170.73 - - 60,469.89 - - 13,278 - - 11,876.49 - - 29,741.49 - - 13,760 - - 12,294.24 - - 30,728.40 -
      - All Media - - All Products - - Non-Consumable - - Periodicals - - All Marital Status - - 4,294 - - 3,614.55 - - 9,056.76 - - 2,168 - - 1,833.48 - - 4,583.08 - - 2,126 - - 1,781.08 - - 4,473.68 -
      +   + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender +
      + F + + F + + F + + M + + M + + M +
      + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + All Products + + All Marital Status + + 266,773 + + 225,627.23 + + 565,238.13 + + 131,558 + + 111,777.48 + + 280,226.21 + + 135,215 + + 113,849.75 + + 285,011.92 +
      + All Media + + All Products + + Drink + + All Marital Status + + 24,597 + + 19,477.23 + + 48,836.21 + + 12,202 + + 9,751.10 + + 24,457.37 + + 12,395 + + 9,726.14 + + 24,378.84 +
      + All Media + + All Products + + Food + + All Marital Status + + 191,940 + + 163,270.72 + + 409,035.59 + + 94,814 + + 80,993.45 + + 203,094.17 + + 97,126 + + 82,277.27 + + 205,941.42 +
      + All Media + + All Products + + Food + + Baked Goods + + All Marital Status + + 7,870 + + 6,564.09 + + 16,455.43 + + 3,771 + + 3,164.76 + + 7,938.38 + + 4,099 + + 3,399.34 + + 8,517.05 +
      + All Media + + All Products + + Food + + Baking Goods + + All Marital Status + + 20,245 + + 15,370.61 + + 38,670.41 + + 9,841 + + 7,389.74 + + 18,608.22 + + 10,404 + + 7,980.87 + + 20,062.19 +
      + All Media + + All Products + + Food + + Baking Goods + + Baking Goods + + All Marital Status + + 8,357 + + 6,123.32 + + 15,446.69 + + 4,005 + + 2,907.70 + + 7,313.61 + + 4,352 + + 3,215.62 + + 8,133.08 +
      + All Media + + All Products + + Food + + Baking Goods + + Baking Goods + + All Marital Status + + M + + 4,167 + + 3,044.62 + + 7,656.25 + + 2,028 + + 1,469.66 + + 3,711.91 + + 2,139 + + 1,574.96 + + 3,944.34 +
      + All Media + + All Products + + Food + + Baking Goods + + Baking Goods + + All Marital Status + + S + + 4,190 + + 3,078.70 + + 7,790.44 + + 1,977 + + 1,438.04 + + 3,601.70 + + 2,213 + + 1,640.66 + + 4,188.74 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + All Marital Status + + 11,888 + + 9,247.29 + + 23,223.72 + + 5,836 + + 4,482.04 + + 11,294.61 + + 6,052 + + 4,765.25 + + 11,929.11 +
      + All Media + + All Products + + Food + + Breakfast Foods + + All Marital Status + + 3,317 + + 2,756.80 + + 6,941.46 + + 1,821 + + 1,522.93 + + 3,840.30 + + 1,496 + + 1,233.87 + + 3,101.16 +
      + All Media + + All Products + + Food + + Canned Foods + + All Marital Status + + 19,026 + + 15,894.53 + + 39,774.34 + + 9,407 + + 7,942.57 + + 19,864.15 + + 9,619 + + 7,951.97 + + 19,910.19 +
      + All Media + + All Products + + Food + + Canned Products + + All Marital Status + + 1,812 + + 1,317.13 + + 3,314.52 + + 867 + + 613.76 + + 1,551.30 + + 945 + + 703.37 + + 1,763.22 +
      + All Media + + All Products + + Food + + Dairy + + All Marital Status + + 12,885 + + 12,228.85 + + 30,508.85 + + 6,513 + + 6,253.73 + + 15,603.84 + + 6,372 + + 5,975.12 + + 14,905.01 +
      + All Media + + All Products + + Food + + Deli + + All Marital Status + + 12,037 + + 10,108.87 + + 25,318.93 + + 5,990 + + 5,022.05 + + 12,592.39 + + 6,047 + + 5,086.82 + + 12,726.54 +
      + All Media + + All Products + + Food + + Eggs + + All Marital Status + + 4,132 + + 3,684.90 + + 9,200.76 + + 2,001 + + 1,746.06 + + 4,355.68 + + 2,131 + + 1,938.84 + + 4,845.08 +
      + All Media + + All Products + + Food + + Frozen Foods + + All Marital Status + + 26,655 + + 22,030.66 + + 55,207.50 + + 13,011 + + 10,843.01 + + 27,168.52 + + 13,644 + + 11,187.65 + + 28,038.98 +
      + All Media + + All Products + + Food + + Meat + + All Marital Status + + 1,714 + + 1,465.42 + + 3,669.89 + + 841 + + 716.84 + + 1,797.60 + + 873 + + 748.59 + + 1,872.29 +
      + All Media + + All Products + + Food + + Produce + + All Marital Status + + 37,792 + + 32,831.33 + + 82,248.42 + + 18,713 + + 16,403.72 + + 41,069.39 + + 19,079 + + 16,427.61 + + 41,179.03 +
      + All Media + + All Products + + Food + + Seafood + + All Marital Status + + 1,764 + + 1,520.70 + + 3,809.14 + + 947 + + 836.19 + + 2,095.55 + + 817 + + 684.51 + + 1,713.59 +
      + All Media + + All Products + + Food + + Snack Foods + + All Marital Status + + 30,545 + + 26,963.34 + + 67,609.82 + + 14,936 + + 13,160.27 + + 33,120.45 + + 15,609 + + 13,803.07 + + 34,489.37 +
      + All Media + + All Products + + Food + + Snacks + + All Marital Status + + 6,884 + + 5,827.58 + + 14,550.05 + + 3,459 + + 2,960.73 + + 7,430.30 + + 3,425 + + 2,866.86 + + 7,119.75 +
      + All Media + + All Products + + Food + + Starchy Foods + + All Marital Status + + 5,262 + + 4,705.91 + + 11,756.07 + + 2,696 + + 2,417.11 + + 6,058.10 + + 2,566 + + 2,288.79 + + 5,697.97 +
      + All Media + + All Products + + Non-Consumable + + All Marital Status + + 50,236 + + 42,879.28 + + 107,366.33 + + 24,542 + + 21,032.93 + + 52,674.67 + + 25,694 + + 21,846.35 + + 54,691.66 +
      + All Media + + All Products + + Non-Consumable + + Carousel + + All Marital Status + + 841 + + 595.97 + + 1,500.11 + + 368 + + 258.40 + + 655.55 + + 473 + + 337.57 + + 844.56 +
      + All Media + + All Products + + Non-Consumable + + Checkout + + All Marital Status + + 1,779 + + 1,525.04 + + 3,767.71 + + 887 + + 755.83 + + 1,874.82 + + 892 + + 769.21 + + 1,892.89 +
      + All Media + + All Products + + Non-Consumable + + Health and Hygiene + + All Marital Status + + 16,284 + + 12,972.99 + + 32,571.86 + + 7,841 + + 6,308.73 + + 15,819.73 + + 8,443 + + 6,664.25 + + 16,752.13 +
      + All Media + + All Products + + Non-Consumable + + Household + + All Marital Status + + 27,038 + + 24,170.73 + + 60,469.89 + + 13,278 + + 11,876.49 + + 29,741.49 + + 13,760 + + 12,294.24 + + 30,728.40 +
      + All Media + + All Products + + Non-Consumable + + Periodicals + + All Marital Status + + 4,294 + + 3,614.55 + + 9,056.76 + + 2,168 + + 1,833.48 + + 4,583.08 + + 2,126 + + 1,781.08 + + 4,473.68 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/basic-true-true-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/basic-true-true-false-result.html index f9a88156..b5772f55 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/basic-true-true-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/basic-true-true-false-result.html @@ -1,1198 +1,1198 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender -
      - All Gender - - All Gender - - All Gender - - F - - F - - F - - M - - M - - M -
      - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures -
      - Promotion Media - - Product - - Marital Status - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - All Products - - All Marital Status - - 266,773 - - 225,627.23 - - 565,238.13 - - 131,558 - - 111,777.48 - - 280,226.21 - - 135,215 - - 113,849.75 - - 285,011.92 -
      - All Media - - Drink - - All Marital Status - - 24,597 - - 19,477.23 - - 48,836.21 - - 12,202 - - 9,751.10 - - 24,457.37 - - 12,395 - - 9,726.14 - - 24,378.84 -
      - All Media - - Food - - All Marital Status - - 191,940 - - 163,270.72 - - 409,035.59 - - 94,814 - - 80,993.45 - - 203,094.17 - - 97,126 - - 82,277.27 - - 205,941.42 -
      - All Media - - Baked Goods - - All Marital Status - - 7,870 - - 6,564.09 - - 16,455.43 - - 3,771 - - 3,164.76 - - 7,938.38 - - 4,099 - - 3,399.34 - - 8,517.05 -
      - All Media - - Baking Goods - - All Marital Status - - 20,245 - - 15,370.61 - - 38,670.41 - - 9,841 - - 7,389.74 - - 18,608.22 - - 10,404 - - 7,980.87 - - 20,062.19 -
      - All Media - - Baking Goods - - All Marital Status - - 8,357 - - 6,123.32 - - 15,446.69 - - 4,005 - - 2,907.70 - - 7,313.61 - - 4,352 - - 3,215.62 - - 8,133.08 -
      - All Media - - Baking Goods - - M - - 4,167 - - 3,044.62 - - 7,656.25 - - 2,028 - - 1,469.66 - - 3,711.91 - - 2,139 - - 1,574.96 - - 3,944.34 -
      - All Media - - Baking Goods - - S - - 4,190 - - 3,078.70 - - 7,790.44 - - 1,977 - - 1,438.04 - - 3,601.70 - - 2,213 - - 1,640.66 - - 4,188.74 -
      - All Media - - Jams and Jellies - - All Marital Status - - 11,888 - - 9,247.29 - - 23,223.72 - - 5,836 - - 4,482.04 - - 11,294.61 - - 6,052 - - 4,765.25 - - 11,929.11 -
      - All Media - - Breakfast Foods - - All Marital Status - - 3,317 - - 2,756.80 - - 6,941.46 - - 1,821 - - 1,522.93 - - 3,840.30 - - 1,496 - - 1,233.87 - - 3,101.16 -
      - All Media - - Canned Foods - - All Marital Status - - 19,026 - - 15,894.53 - - 39,774.34 - - 9,407 - - 7,942.57 - - 19,864.15 - - 9,619 - - 7,951.97 - - 19,910.19 -
      - All Media - - Canned Products - - All Marital Status - - 1,812 - - 1,317.13 - - 3,314.52 - - 867 - - 613.76 - - 1,551.30 - - 945 - - 703.37 - - 1,763.22 -
      - All Media - - Dairy - - All Marital Status - - 12,885 - - 12,228.85 - - 30,508.85 - - 6,513 - - 6,253.73 - - 15,603.84 - - 6,372 - - 5,975.12 - - 14,905.01 -
      - All Media - - Deli - - All Marital Status - - 12,037 - - 10,108.87 - - 25,318.93 - - 5,990 - - 5,022.05 - - 12,592.39 - - 6,047 - - 5,086.82 - - 12,726.54 -
      - All Media - - Eggs - - All Marital Status - - 4,132 - - 3,684.90 - - 9,200.76 - - 2,001 - - 1,746.06 - - 4,355.68 - - 2,131 - - 1,938.84 - - 4,845.08 -
      - All Media - - Frozen Foods - - All Marital Status - - 26,655 - - 22,030.66 - - 55,207.50 - - 13,011 - - 10,843.01 - - 27,168.52 - - 13,644 - - 11,187.65 - - 28,038.98 -
      - All Media - - Meat - - All Marital Status - - 1,714 - - 1,465.42 - - 3,669.89 - - 841 - - 716.84 - - 1,797.60 - - 873 - - 748.59 - - 1,872.29 -
      - All Media - - Produce - - All Marital Status - - 37,792 - - 32,831.33 - - 82,248.42 - - 18,713 - - 16,403.72 - - 41,069.39 - - 19,079 - - 16,427.61 - - 41,179.03 -
      - All Media - - Seafood - - All Marital Status - - 1,764 - - 1,520.70 - - 3,809.14 - - 947 - - 836.19 - - 2,095.55 - - 817 - - 684.51 - - 1,713.59 -
      - All Media - - Snack Foods - - All Marital Status - - 30,545 - - 26,963.34 - - 67,609.82 - - 14,936 - - 13,160.27 - - 33,120.45 - - 15,609 - - 13,803.07 - - 34,489.37 -
      - All Media - - Snacks - - All Marital Status - - 6,884 - - 5,827.58 - - 14,550.05 - - 3,459 - - 2,960.73 - - 7,430.30 - - 3,425 - - 2,866.86 - - 7,119.75 -
      - All Media - - Starchy Foods - - All Marital Status - - 5,262 - - 4,705.91 - - 11,756.07 - - 2,696 - - 2,417.11 - - 6,058.10 - - 2,566 - - 2,288.79 - - 5,697.97 -
      - All Media - - Non-Consumable - - All Marital Status - - 50,236 - - 42,879.28 - - 107,366.33 - - 24,542 - - 21,032.93 - - 52,674.67 - - 25,694 - - 21,846.35 - - 54,691.66 -
      - All Media - - Carousel - - All Marital Status - - 841 - - 595.97 - - 1,500.11 - - 368 - - 258.40 - - 655.55 - - 473 - - 337.57 - - 844.56 -
      - All Media - - Checkout - - All Marital Status - - 1,779 - - 1,525.04 - - 3,767.71 - - 887 - - 755.83 - - 1,874.82 - - 892 - - 769.21 - - 1,892.89 -
      - All Media - - Health and Hygiene - - All Marital Status - - 16,284 - - 12,972.99 - - 32,571.86 - - 7,841 - - 6,308.73 - - 15,819.73 - - 8,443 - - 6,664.25 - - 16,752.13 -
      - All Media - - Household - - All Marital Status - - 27,038 - - 24,170.73 - - 60,469.89 - - 13,278 - - 11,876.49 - - 29,741.49 - - 13,760 - - 12,294.24 - - 30,728.40 -
      - All Media - - Periodicals - - All Marital Status - - 4,294 - - 3,614.55 - - 9,056.76 - - 2,168 - - 1,833.48 - - 4,583.08 - - 2,126 - - 1,781.08 - - 4,473.68 -
      +   + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender +
      + All Gender + + All Gender + + All Gender + + F + + F + + F + + M + + M + + M +
      + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures +
      + Promotion Media + + Product + + Marital Status + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + All Products + + All Marital Status + + 266,773 + + 225,627.23 + + 565,238.13 + + 131,558 + + 111,777.48 + + 280,226.21 + + 135,215 + + 113,849.75 + + 285,011.92 +
      + All Media + + Drink + + All Marital Status + + 24,597 + + 19,477.23 + + 48,836.21 + + 12,202 + + 9,751.10 + + 24,457.37 + + 12,395 + + 9,726.14 + + 24,378.84 +
      + All Media + + Food + + All Marital Status + + 191,940 + + 163,270.72 + + 409,035.59 + + 94,814 + + 80,993.45 + + 203,094.17 + + 97,126 + + 82,277.27 + + 205,941.42 +
      + All Media + + Baked Goods + + All Marital Status + + 7,870 + + 6,564.09 + + 16,455.43 + + 3,771 + + 3,164.76 + + 7,938.38 + + 4,099 + + 3,399.34 + + 8,517.05 +
      + All Media + + Baking Goods + + All Marital Status + + 20,245 + + 15,370.61 + + 38,670.41 + + 9,841 + + 7,389.74 + + 18,608.22 + + 10,404 + + 7,980.87 + + 20,062.19 +
      + All Media + + Baking Goods + + All Marital Status + + 8,357 + + 6,123.32 + + 15,446.69 + + 4,005 + + 2,907.70 + + 7,313.61 + + 4,352 + + 3,215.62 + + 8,133.08 +
      + All Media + + Baking Goods + + M + + 4,167 + + 3,044.62 + + 7,656.25 + + 2,028 + + 1,469.66 + + 3,711.91 + + 2,139 + + 1,574.96 + + 3,944.34 +
      + All Media + + Baking Goods + + S + + 4,190 + + 3,078.70 + + 7,790.44 + + 1,977 + + 1,438.04 + + 3,601.70 + + 2,213 + + 1,640.66 + + 4,188.74 +
      + All Media + + Jams and Jellies + + All Marital Status + + 11,888 + + 9,247.29 + + 23,223.72 + + 5,836 + + 4,482.04 + + 11,294.61 + + 6,052 + + 4,765.25 + + 11,929.11 +
      + All Media + + Breakfast Foods + + All Marital Status + + 3,317 + + 2,756.80 + + 6,941.46 + + 1,821 + + 1,522.93 + + 3,840.30 + + 1,496 + + 1,233.87 + + 3,101.16 +
      + All Media + + Canned Foods + + All Marital Status + + 19,026 + + 15,894.53 + + 39,774.34 + + 9,407 + + 7,942.57 + + 19,864.15 + + 9,619 + + 7,951.97 + + 19,910.19 +
      + All Media + + Canned Products + + All Marital Status + + 1,812 + + 1,317.13 + + 3,314.52 + + 867 + + 613.76 + + 1,551.30 + + 945 + + 703.37 + + 1,763.22 +
      + All Media + + Dairy + + All Marital Status + + 12,885 + + 12,228.85 + + 30,508.85 + + 6,513 + + 6,253.73 + + 15,603.84 + + 6,372 + + 5,975.12 + + 14,905.01 +
      + All Media + + Deli + + All Marital Status + + 12,037 + + 10,108.87 + + 25,318.93 + + 5,990 + + 5,022.05 + + 12,592.39 + + 6,047 + + 5,086.82 + + 12,726.54 +
      + All Media + + Eggs + + All Marital Status + + 4,132 + + 3,684.90 + + 9,200.76 + + 2,001 + + 1,746.06 + + 4,355.68 + + 2,131 + + 1,938.84 + + 4,845.08 +
      + All Media + + Frozen Foods + + All Marital Status + + 26,655 + + 22,030.66 + + 55,207.50 + + 13,011 + + 10,843.01 + + 27,168.52 + + 13,644 + + 11,187.65 + + 28,038.98 +
      + All Media + + Meat + + All Marital Status + + 1,714 + + 1,465.42 + + 3,669.89 + + 841 + + 716.84 + + 1,797.60 + + 873 + + 748.59 + + 1,872.29 +
      + All Media + + Produce + + All Marital Status + + 37,792 + + 32,831.33 + + 82,248.42 + + 18,713 + + 16,403.72 + + 41,069.39 + + 19,079 + + 16,427.61 + + 41,179.03 +
      + All Media + + Seafood + + All Marital Status + + 1,764 + + 1,520.70 + + 3,809.14 + + 947 + + 836.19 + + 2,095.55 + + 817 + + 684.51 + + 1,713.59 +
      + All Media + + Snack Foods + + All Marital Status + + 30,545 + + 26,963.34 + + 67,609.82 + + 14,936 + + 13,160.27 + + 33,120.45 + + 15,609 + + 13,803.07 + + 34,489.37 +
      + All Media + + Snacks + + All Marital Status + + 6,884 + + 5,827.58 + + 14,550.05 + + 3,459 + + 2,960.73 + + 7,430.30 + + 3,425 + + 2,866.86 + + 7,119.75 +
      + All Media + + Starchy Foods + + All Marital Status + + 5,262 + + 4,705.91 + + 11,756.07 + + 2,696 + + 2,417.11 + + 6,058.10 + + 2,566 + + 2,288.79 + + 5,697.97 +
      + All Media + + Non-Consumable + + All Marital Status + + 50,236 + + 42,879.28 + + 107,366.33 + + 24,542 + + 21,032.93 + + 52,674.67 + + 25,694 + + 21,846.35 + + 54,691.66 +
      + All Media + + Carousel + + All Marital Status + + 841 + + 595.97 + + 1,500.11 + + 368 + + 258.40 + + 655.55 + + 473 + + 337.57 + + 844.56 +
      + All Media + + Checkout + + All Marital Status + + 1,779 + + 1,525.04 + + 3,767.71 + + 887 + + 755.83 + + 1,874.82 + + 892 + + 769.21 + + 1,892.89 +
      + All Media + + Health and Hygiene + + All Marital Status + + 16,284 + + 12,972.99 + + 32,571.86 + + 7,841 + + 6,308.73 + + 15,819.73 + + 8,443 + + 6,664.25 + + 16,752.13 +
      + All Media + + Household + + All Marital Status + + 27,038 + + 24,170.73 + + 60,469.89 + + 13,278 + + 11,876.49 + + 29,741.49 + + 13,760 + + 12,294.24 + + 30,728.40 +
      + All Media + + Periodicals + + All Marital Status + + 4,294 + + 3,614.55 + + 9,056.76 + + 2,168 + + 1,833.48 + + 4,583.08 + + 2,126 + + 1,781.08 + + 4,473.68 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/basic-true-true-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/basic-true-true-true-result.html index b4a02230..cc30e46a 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/basic-true-true-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/basic-true-true-true-result.html @@ -1,1410 +1,1410 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender -
      - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender -
      - F - - F - - F - - M - - M - - M -
      - Promotion Media - - Product - - Marital Status - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures -
      - (All) - - (All) - - Product Family - - Product Department - - Product Category - - (All) - - Marital Status - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - All Products - - All Marital Status - - 266,773 - - 225,627.23 - - 565,238.13 - - 131,558 - - 111,777.48 - - 280,226.21 - - 135,215 - - 113,849.75 - - 285,011.92 -
      - All Media - - All Products - - Drink - - All Marital Status - - 24,597 - - 19,477.23 - - 48,836.21 - - 12,202 - - 9,751.10 - - 24,457.37 - - 12,395 - - 9,726.14 - - 24,378.84 -
      - All Media - - All Products - - Food - - All Marital Status - - 191,940 - - 163,270.72 - - 409,035.59 - - 94,814 - - 80,993.45 - - 203,094.17 - - 97,126 - - 82,277.27 - - 205,941.42 -
      - All Media - - All Products - - Food - - Baked Goods - - All Marital Status - - 7,870 - - 6,564.09 - - 16,455.43 - - 3,771 - - 3,164.76 - - 7,938.38 - - 4,099 - - 3,399.34 - - 8,517.05 -
      - All Media - - All Products - - Food - - Baking Goods - - All Marital Status - - 20,245 - - 15,370.61 - - 38,670.41 - - 9,841 - - 7,389.74 - - 18,608.22 - - 10,404 - - 7,980.87 - - 20,062.19 -
      - All Media - - All Products - - Food - - Baking Goods - - Baking Goods - - All Marital Status - - 8,357 - - 6,123.32 - - 15,446.69 - - 4,005 - - 2,907.70 - - 7,313.61 - - 4,352 - - 3,215.62 - - 8,133.08 -
      - All Media - - All Products - - Food - - Baking Goods - - Baking Goods - - All Marital Status - - M - - 4,167 - - 3,044.62 - - 7,656.25 - - 2,028 - - 1,469.66 - - 3,711.91 - - 2,139 - - 1,574.96 - - 3,944.34 -
      - All Media - - All Products - - Food - - Baking Goods - - Baking Goods - - All Marital Status - - S - - 4,190 - - 3,078.70 - - 7,790.44 - - 1,977 - - 1,438.04 - - 3,601.70 - - 2,213 - - 1,640.66 - - 4,188.74 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - All Marital Status - - 11,888 - - 9,247.29 - - 23,223.72 - - 5,836 - - 4,482.04 - - 11,294.61 - - 6,052 - - 4,765.25 - - 11,929.11 -
      - All Media - - All Products - - Food - - Breakfast Foods - - All Marital Status - - 3,317 - - 2,756.80 - - 6,941.46 - - 1,821 - - 1,522.93 - - 3,840.30 - - 1,496 - - 1,233.87 - - 3,101.16 -
      - All Media - - All Products - - Food - - Canned Foods - - All Marital Status - - 19,026 - - 15,894.53 - - 39,774.34 - - 9,407 - - 7,942.57 - - 19,864.15 - - 9,619 - - 7,951.97 - - 19,910.19 -
      - All Media - - All Products - - Food - - Canned Products - - All Marital Status - - 1,812 - - 1,317.13 - - 3,314.52 - - 867 - - 613.76 - - 1,551.30 - - 945 - - 703.37 - - 1,763.22 -
      - All Media - - All Products - - Food - - Dairy - - All Marital Status - - 12,885 - - 12,228.85 - - 30,508.85 - - 6,513 - - 6,253.73 - - 15,603.84 - - 6,372 - - 5,975.12 - - 14,905.01 -
      - All Media - - All Products - - Food - - Deli - - All Marital Status - - 12,037 - - 10,108.87 - - 25,318.93 - - 5,990 - - 5,022.05 - - 12,592.39 - - 6,047 - - 5,086.82 - - 12,726.54 -
      - All Media - - All Products - - Food - - Eggs - - All Marital Status - - 4,132 - - 3,684.90 - - 9,200.76 - - 2,001 - - 1,746.06 - - 4,355.68 - - 2,131 - - 1,938.84 - - 4,845.08 -
      - All Media - - All Products - - Food - - Frozen Foods - - All Marital Status - - 26,655 - - 22,030.66 - - 55,207.50 - - 13,011 - - 10,843.01 - - 27,168.52 - - 13,644 - - 11,187.65 - - 28,038.98 -
      - All Media - - All Products - - Food - - Meat - - All Marital Status - - 1,714 - - 1,465.42 - - 3,669.89 - - 841 - - 716.84 - - 1,797.60 - - 873 - - 748.59 - - 1,872.29 -
      - All Media - - All Products - - Food - - Produce - - All Marital Status - - 37,792 - - 32,831.33 - - 82,248.42 - - 18,713 - - 16,403.72 - - 41,069.39 - - 19,079 - - 16,427.61 - - 41,179.03 -
      - All Media - - All Products - - Food - - Seafood - - All Marital Status - - 1,764 - - 1,520.70 - - 3,809.14 - - 947 - - 836.19 - - 2,095.55 - - 817 - - 684.51 - - 1,713.59 -
      - All Media - - All Products - - Food - - Snack Foods - - All Marital Status - - 30,545 - - 26,963.34 - - 67,609.82 - - 14,936 - - 13,160.27 - - 33,120.45 - - 15,609 - - 13,803.07 - - 34,489.37 -
      - All Media - - All Products - - Food - - Snacks - - All Marital Status - - 6,884 - - 5,827.58 - - 14,550.05 - - 3,459 - - 2,960.73 - - 7,430.30 - - 3,425 - - 2,866.86 - - 7,119.75 -
      - All Media - - All Products - - Food - - Starchy Foods - - All Marital Status - - 5,262 - - 4,705.91 - - 11,756.07 - - 2,696 - - 2,417.11 - - 6,058.10 - - 2,566 - - 2,288.79 - - 5,697.97 -
      - All Media - - All Products - - Non-Consumable - - All Marital Status - - 50,236 - - 42,879.28 - - 107,366.33 - - 24,542 - - 21,032.93 - - 52,674.67 - - 25,694 - - 21,846.35 - - 54,691.66 -
      - All Media - - All Products - - Non-Consumable - - Carousel - - All Marital Status - - 841 - - 595.97 - - 1,500.11 - - 368 - - 258.40 - - 655.55 - - 473 - - 337.57 - - 844.56 -
      - All Media - - All Products - - Non-Consumable - - Checkout - - All Marital Status - - 1,779 - - 1,525.04 - - 3,767.71 - - 887 - - 755.83 - - 1,874.82 - - 892 - - 769.21 - - 1,892.89 -
      - All Media - - All Products - - Non-Consumable - - Health and Hygiene - - All Marital Status - - 16,284 - - 12,972.99 - - 32,571.86 - - 7,841 - - 6,308.73 - - 15,819.73 - - 8,443 - - 6,664.25 - - 16,752.13 -
      - All Media - - All Products - - Non-Consumable - - Household - - All Marital Status - - 27,038 - - 24,170.73 - - 60,469.89 - - 13,278 - - 11,876.49 - - 29,741.49 - - 13,760 - - 12,294.24 - - 30,728.40 -
      - All Media - - All Products - - Non-Consumable - - Periodicals - - All Marital Status - - 4,294 - - 3,614.55 - - 9,056.76 - - 2,168 - - 1,833.48 - - 4,583.08 - - 2,126 - - 1,781.08 - - 4,473.68 -
      +   + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender +
      + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender +
      + F + + F + + F + + M + + M + + M +
      + Promotion Media + + Product + + Marital Status + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures +
      + (All) + + (All) + + Product Family + + Product Department + + Product Category + + (All) + + Marital Status + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + All Products + + All Marital Status + + 266,773 + + 225,627.23 + + 565,238.13 + + 131,558 + + 111,777.48 + + 280,226.21 + + 135,215 + + 113,849.75 + + 285,011.92 +
      + All Media + + All Products + + Drink + + All Marital Status + + 24,597 + + 19,477.23 + + 48,836.21 + + 12,202 + + 9,751.10 + + 24,457.37 + + 12,395 + + 9,726.14 + + 24,378.84 +
      + All Media + + All Products + + Food + + All Marital Status + + 191,940 + + 163,270.72 + + 409,035.59 + + 94,814 + + 80,993.45 + + 203,094.17 + + 97,126 + + 82,277.27 + + 205,941.42 +
      + All Media + + All Products + + Food + + Baked Goods + + All Marital Status + + 7,870 + + 6,564.09 + + 16,455.43 + + 3,771 + + 3,164.76 + + 7,938.38 + + 4,099 + + 3,399.34 + + 8,517.05 +
      + All Media + + All Products + + Food + + Baking Goods + + All Marital Status + + 20,245 + + 15,370.61 + + 38,670.41 + + 9,841 + + 7,389.74 + + 18,608.22 + + 10,404 + + 7,980.87 + + 20,062.19 +
      + All Media + + All Products + + Food + + Baking Goods + + Baking Goods + + All Marital Status + + 8,357 + + 6,123.32 + + 15,446.69 + + 4,005 + + 2,907.70 + + 7,313.61 + + 4,352 + + 3,215.62 + + 8,133.08 +
      + All Media + + All Products + + Food + + Baking Goods + + Baking Goods + + All Marital Status + + M + + 4,167 + + 3,044.62 + + 7,656.25 + + 2,028 + + 1,469.66 + + 3,711.91 + + 2,139 + + 1,574.96 + + 3,944.34 +
      + All Media + + All Products + + Food + + Baking Goods + + Baking Goods + + All Marital Status + + S + + 4,190 + + 3,078.70 + + 7,790.44 + + 1,977 + + 1,438.04 + + 3,601.70 + + 2,213 + + 1,640.66 + + 4,188.74 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + All Marital Status + + 11,888 + + 9,247.29 + + 23,223.72 + + 5,836 + + 4,482.04 + + 11,294.61 + + 6,052 + + 4,765.25 + + 11,929.11 +
      + All Media + + All Products + + Food + + Breakfast Foods + + All Marital Status + + 3,317 + + 2,756.80 + + 6,941.46 + + 1,821 + + 1,522.93 + + 3,840.30 + + 1,496 + + 1,233.87 + + 3,101.16 +
      + All Media + + All Products + + Food + + Canned Foods + + All Marital Status + + 19,026 + + 15,894.53 + + 39,774.34 + + 9,407 + + 7,942.57 + + 19,864.15 + + 9,619 + + 7,951.97 + + 19,910.19 +
      + All Media + + All Products + + Food + + Canned Products + + All Marital Status + + 1,812 + + 1,317.13 + + 3,314.52 + + 867 + + 613.76 + + 1,551.30 + + 945 + + 703.37 + + 1,763.22 +
      + All Media + + All Products + + Food + + Dairy + + All Marital Status + + 12,885 + + 12,228.85 + + 30,508.85 + + 6,513 + + 6,253.73 + + 15,603.84 + + 6,372 + + 5,975.12 + + 14,905.01 +
      + All Media + + All Products + + Food + + Deli + + All Marital Status + + 12,037 + + 10,108.87 + + 25,318.93 + + 5,990 + + 5,022.05 + + 12,592.39 + + 6,047 + + 5,086.82 + + 12,726.54 +
      + All Media + + All Products + + Food + + Eggs + + All Marital Status + + 4,132 + + 3,684.90 + + 9,200.76 + + 2,001 + + 1,746.06 + + 4,355.68 + + 2,131 + + 1,938.84 + + 4,845.08 +
      + All Media + + All Products + + Food + + Frozen Foods + + All Marital Status + + 26,655 + + 22,030.66 + + 55,207.50 + + 13,011 + + 10,843.01 + + 27,168.52 + + 13,644 + + 11,187.65 + + 28,038.98 +
      + All Media + + All Products + + Food + + Meat + + All Marital Status + + 1,714 + + 1,465.42 + + 3,669.89 + + 841 + + 716.84 + + 1,797.60 + + 873 + + 748.59 + + 1,872.29 +
      + All Media + + All Products + + Food + + Produce + + All Marital Status + + 37,792 + + 32,831.33 + + 82,248.42 + + 18,713 + + 16,403.72 + + 41,069.39 + + 19,079 + + 16,427.61 + + 41,179.03 +
      + All Media + + All Products + + Food + + Seafood + + All Marital Status + + 1,764 + + 1,520.70 + + 3,809.14 + + 947 + + 836.19 + + 2,095.55 + + 817 + + 684.51 + + 1,713.59 +
      + All Media + + All Products + + Food + + Snack Foods + + All Marital Status + + 30,545 + + 26,963.34 + + 67,609.82 + + 14,936 + + 13,160.27 + + 33,120.45 + + 15,609 + + 13,803.07 + + 34,489.37 +
      + All Media + + All Products + + Food + + Snacks + + All Marital Status + + 6,884 + + 5,827.58 + + 14,550.05 + + 3,459 + + 2,960.73 + + 7,430.30 + + 3,425 + + 2,866.86 + + 7,119.75 +
      + All Media + + All Products + + Food + + Starchy Foods + + All Marital Status + + 5,262 + + 4,705.91 + + 11,756.07 + + 2,696 + + 2,417.11 + + 6,058.10 + + 2,566 + + 2,288.79 + + 5,697.97 +
      + All Media + + All Products + + Non-Consumable + + All Marital Status + + 50,236 + + 42,879.28 + + 107,366.33 + + 24,542 + + 21,032.93 + + 52,674.67 + + 25,694 + + 21,846.35 + + 54,691.66 +
      + All Media + + All Products + + Non-Consumable + + Carousel + + All Marital Status + + 841 + + 595.97 + + 1,500.11 + + 368 + + 258.40 + + 655.55 + + 473 + + 337.57 + + 844.56 +
      + All Media + + All Products + + Non-Consumable + + Checkout + + All Marital Status + + 1,779 + + 1,525.04 + + 3,767.71 + + 887 + + 755.83 + + 1,874.82 + + 892 + + 769.21 + + 1,892.89 +
      + All Media + + All Products + + Non-Consumable + + Health and Hygiene + + All Marital Status + + 16,284 + + 12,972.99 + + 32,571.86 + + 7,841 + + 6,308.73 + + 15,819.73 + + 8,443 + + 6,664.25 + + 16,752.13 +
      + All Media + + All Products + + Non-Consumable + + Household + + All Marital Status + + 27,038 + + 24,170.73 + + 60,469.89 + + 13,278 + + 11,876.49 + + 29,741.49 + + 13,760 + + 12,294.24 + + 30,728.40 +
      + All Media + + All Products + + Non-Consumable + + Periodicals + + All Marital Status + + 4,294 + + 3,614.55 + + 9,056.76 + + 2,168 + + 1,833.48 + + 4,583.08 + + 2,126 + + 1,781.08 + + 4,473.68 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-columns-false-false-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-columns-false-false-false-result.html index 764b92d0..25ddb182 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-columns-false-false-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-columns-false-false-false-result.html @@ -1,176 +1,176 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - All Gender - - F - - M -
      - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales -
      - All Products - - All Products - - Drink - - Food - - Non-Consumable - - All Products - - All Products - - All Products - - All Products - - Drink - - Food - - Non-Consumable - - Carousel - - Checkout - - Health and Hygiene - - Household - - Periodicals - - All Products - - All Products - - All Products -
      - All Media - - 266,773 - - 225,627.23 - - 19,477.23 - - 163,270.72 - - 42,879.28 - - 565,238.13 - - 131,558 - - 111,777.48 - - 280,226.21 - - 24,457.37 - - 203,094.17 - - 52,674.67 - - 655.55 - - 1,874.82 - - 15,819.73 - - 29,741.49 - - 4,583.08 - - 135,215 - - 113,849.75 - - 285,011.92 -
      +   + + All Gender + + F + + M +
      + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales +
      + All Products + + All Products + + Drink + + Food + + Non-Consumable + + All Products + + All Products + + All Products + + All Products + + Drink + + Food + + Non-Consumable + + Carousel + + Checkout + + Health and Hygiene + + Household + + Periodicals + + All Products + + All Products + + All Products +
      + All Media + + 266,773 + + 225,627.23 + + 19,477.23 + + 163,270.72 + + 42,879.28 + + 565,238.13 + + 131,558 + + 111,777.48 + + 280,226.21 + + 24,457.37 + + 203,094.17 + + 52,674.67 + + 655.55 + + 1,874.82 + + 15,819.73 + + 29,741.49 + + 4,583.08 + + 135,215 + + 113,849.75 + + 285,011.92 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-columns-false-false-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-columns-false-false-true-result.html index 086c5f12..abff4590 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-columns-false-false-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-columns-false-false-true-result.html @@ -1,194 +1,194 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - All Gender - - All Gender -
      - F - - M -
      - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales -
      - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products -
      - Drink - - Food - - Non-Consumable - - Drink - - Food - - Non-Consumable - - Non-Consumable -
      - Carousel - - Checkout - - Health and Hygiene - - Household - - Periodicals -
      - All Media - - 266,773 - - 225,627.23 - - 19,477.23 - - 163,270.72 - - 42,879.28 - - 565,238.13 - - 131,558 - - 111,777.48 - - 280,226.21 - - 24,457.37 - - 203,094.17 - - 52,674.67 - - 655.55 - - 1,874.82 - - 15,819.73 - - 29,741.49 - - 4,583.08 - - 135,215 - - 113,849.75 - - 285,011.92 -
      +   + + All Gender + + All Gender +
      + F + + M +
      + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales +
      + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products +
      + Drink + + Food + + Non-Consumable + + Drink + + Food + + Non-Consumable + + Non-Consumable +
      + Carousel + + Checkout + + Health and Hygiene + + Household + + Periodicals +
      + All Media + + 266,773 + + 225,627.23 + + 19,477.23 + + 163,270.72 + + 42,879.28 + + 565,238.13 + + 131,558 + + 111,777.48 + + 280,226.21 + + 24,457.37 + + 203,094.17 + + 52,674.67 + + 655.55 + + 1,874.82 + + 15,819.73 + + 29,741.49 + + 4,583.08 + + 135,215 + + 113,849.75 + + 285,011.92 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-columns-false-true-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-columns-false-true-false-result.html index 0c2bc330..68aa7b27 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-columns-false-true-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-columns-false-true-false-result.html @@ -1,224 +1,224 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Gender -
      - All Gender - - F - - M -
      - Measures - - Measures - - Measures -
      - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales -
      - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product -
      - Promotion Media - - All Products - - All Products - - Drink - - Food - - Non-Consumable - - All Products - - All Products - - All Products - - All Products - - Drink - - Food - - Non-Consumable - - Carousel - - Checkout - - Health and Hygiene - - Household - - Periodicals - - All Products - - All Products - - All Products -
      - All Media - - 266,773 - - 225,627.23 - - 19,477.23 - - 163,270.72 - - 42,879.28 - - 565,238.13 - - 131,558 - - 111,777.48 - - 280,226.21 - - 24,457.37 - - 203,094.17 - - 52,674.67 - - 655.55 - - 1,874.82 - - 15,819.73 - - 29,741.49 - - 4,583.08 - - 135,215 - - 113,849.75 - - 285,011.92 -
      +   + + Gender +
      + All Gender + + F + + M +
      + Measures + + Measures + + Measures +
      + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales +
      + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product +
      + Promotion Media + + All Products + + All Products + + Drink + + Food + + Non-Consumable + + All Products + + All Products + + All Products + + All Products + + Drink + + Food + + Non-Consumable + + Carousel + + Checkout + + Health and Hygiene + + Household + + Periodicals + + All Products + + All Products + + All Products +
      + All Media + + 266,773 + + 225,627.23 + + 19,477.23 + + 163,270.72 + + 42,879.28 + + 565,238.13 + + 131,558 + + 111,777.48 + + 280,226.21 + + 24,457.37 + + 203,094.17 + + 52,674.67 + + 655.55 + + 1,874.82 + + 15,819.73 + + 29,741.49 + + 4,583.08 + + 135,215 + + 113,849.75 + + 285,011.92 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-columns-false-true-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-columns-false-true-true-result.html index 4152096a..1d8a8e87 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-columns-false-true-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-columns-false-true-true-result.html @@ -1,245 +1,245 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Gender -
      - All Gender - - All Gender -
      - F - - M -
      - Measures - - Measures - - Measures -
      - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales -
      - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product -
      - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products -
      - Promotion Media - - Drink - - Food - - Non-Consumable - - Drink - - Food - - Non-Consumable - - Non-Consumable -
      - (All) - - Carousel - - Checkout - - Health and Hygiene - - Household - - Periodicals -
      - All Media - - 266,773 - - 225,627.23 - - 19,477.23 - - 163,270.72 - - 42,879.28 - - 565,238.13 - - 131,558 - - 111,777.48 - - 280,226.21 - - 24,457.37 - - 203,094.17 - - 52,674.67 - - 655.55 - - 1,874.82 - - 15,819.73 - - 29,741.49 - - 4,583.08 - - 135,215 - - 113,849.75 - - 285,011.92 -
      +   + + Gender +
      + All Gender + + All Gender +
      + F + + M +
      + Measures + + Measures + + Measures +
      + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales +
      + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product +
      + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products +
      + Promotion Media + + Drink + + Food + + Non-Consumable + + Drink + + Food + + Non-Consumable + + Non-Consumable +
      + (All) + + Carousel + + Checkout + + Health and Hygiene + + Household + + Periodicals +
      + All Media + + 266,773 + + 225,627.23 + + 19,477.23 + + 163,270.72 + + 42,879.28 + + 565,238.13 + + 131,558 + + 111,777.48 + + 280,226.21 + + 24,457.37 + + 203,094.17 + + 52,674.67 + + 655.55 + + 1,874.82 + + 15,819.73 + + 29,741.49 + + 4,583.08 + + 135,215 + + 113,849.75 + + 285,011.92 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-columns-true-false-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-columns-true-false-false-result.html index 68197c6f..85449eb5 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-columns-true-false-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-columns-true-false-false-result.html @@ -1,260 +1,260 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - F - - F - - F - - F - - F - - F - - F - - F - - F - - F - - F - - M - - M - - M -
      - Unit Sales - - Store Cost - - Store Cost - - Store Cost - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Store Sales - - Store Sales - - Store Sales - - Store Sales - - Store Sales - - Store Sales - - Store Sales - - Store Sales - - Unit Sales - - Store Cost - - Store Sales -
      - All Products - - All Products - - Drink - - Food - - Non-Consumable - - All Products - - All Products - - All Products - - All Products - - Drink - - Food - - Non-Consumable - - Carousel - - Checkout - - Health and Hygiene - - Household - - Periodicals - - All Products - - All Products - - All Products -
      - All Media - - 266,773 - - 225,627.23 - - 19,477.23 - - 163,270.72 - - 42,879.28 - - 565,238.13 - - 131,558 - - 111,777.48 - - 280,226.21 - - 24,457.37 - - 203,094.17 - - 52,674.67 - - 655.55 - - 1,874.82 - - 15,819.73 - - 29,741.49 - - 4,583.08 - - 135,215 - - 113,849.75 - - 285,011.92 -
      +   + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + F + + F + + F + + F + + F + + F + + F + + F + + F + + F + + F + + M + + M + + M +
      + Unit Sales + + Store Cost + + Store Cost + + Store Cost + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Store Sales + + Store Sales + + Store Sales + + Store Sales + + Store Sales + + Store Sales + + Store Sales + + Store Sales + + Unit Sales + + Store Cost + + Store Sales +
      + All Products + + All Products + + Drink + + Food + + Non-Consumable + + All Products + + All Products + + All Products + + All Products + + Drink + + Food + + Non-Consumable + + Carousel + + Checkout + + Health and Hygiene + + Household + + Periodicals + + All Products + + All Products + + All Products +
      + All Media + + 266,773 + + 225,627.23 + + 19,477.23 + + 163,270.72 + + 42,879.28 + + 565,238.13 + + 131,558 + + 111,777.48 + + 280,226.21 + + 24,457.37 + + 203,094.17 + + 52,674.67 + + 655.55 + + 1,874.82 + + 15,819.73 + + 29,741.49 + + 4,583.08 + + 135,215 + + 113,849.75 + + 285,011.92 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-columns-true-false-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-columns-true-false-true-result.html index 628fafff..af97d272 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-columns-true-false-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-columns-true-false-true-result.html @@ -1,356 +1,356 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender -
      - F - - F - - F - - F - - F - - F - - F - - F - - F - - F - - F - - M - - M - - M -
      - Unit Sales - - Store Cost - - Store Cost - - Store Cost - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Store Sales - - Store Sales - - Store Sales - - Store Sales - - Store Sales - - Store Sales - - Store Sales - - Store Sales - - Unit Sales - - Store Cost - - Store Sales -
      - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products -
      - Drink - - Food - - Non-Consumable - - Drink - - Food - - Non-Consumable - - Non-Consumable - - Non-Consumable - - Non-Consumable - - Non-Consumable - - Non-Consumable -
      - Carousel - - Checkout - - Health and Hygiene - - Household - - Periodicals -
      - All Media - - 266,773 - - 225,627.23 - - 19,477.23 - - 163,270.72 - - 42,879.28 - - 565,238.13 - - 131,558 - - 111,777.48 - - 280,226.21 - - 24,457.37 - - 203,094.17 - - 52,674.67 - - 655.55 - - 1,874.82 - - 15,819.73 - - 29,741.49 - - 4,583.08 - - 135,215 - - 113,849.75 - - 285,011.92 -
      +   + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender +
      + F + + F + + F + + F + + F + + F + + F + + F + + F + + F + + F + + M + + M + + M +
      + Unit Sales + + Store Cost + + Store Cost + + Store Cost + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Store Sales + + Store Sales + + Store Sales + + Store Sales + + Store Sales + + Store Sales + + Store Sales + + Store Sales + + Unit Sales + + Store Cost + + Store Sales +
      + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products +
      + Drink + + Food + + Non-Consumable + + Drink + + Food + + Non-Consumable + + Non-Consumable + + Non-Consumable + + Non-Consumable + + Non-Consumable + + Non-Consumable +
      + Carousel + + Checkout + + Health and Hygiene + + Household + + Periodicals +
      + All Media + + 266,773 + + 225,627.23 + + 19,477.23 + + 163,270.72 + + 42,879.28 + + 565,238.13 + + 131,558 + + 111,777.48 + + 280,226.21 + + 24,457.37 + + 203,094.17 + + 52,674.67 + + 655.55 + + 1,874.82 + + 15,819.73 + + 29,741.49 + + 4,583.08 + + 135,215 + + 113,849.75 + + 285,011.92 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-columns-true-true-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-columns-true-true-false-result.html index 88a717ec..3409539c 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-columns-true-true-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-columns-true-true-false-result.html @@ -1,449 +1,449 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender -
      - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - F - - F - - F - - F - - F - - F - - F - - F - - F - - F - - F - - M - - M - - M -
      - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures -
      - Unit Sales - - Store Cost - - Store Cost - - Store Cost - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Store Sales - - Store Sales - - Store Sales - - Store Sales - - Store Sales - - Store Sales - - Store Sales - - Store Sales - - Unit Sales - - Store Cost - - Store Sales -
      - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product -
      - Promotion Media - - All Products - - All Products - - Drink - - Food - - Non-Consumable - - All Products - - All Products - - All Products - - All Products - - Drink - - Food - - Non-Consumable - - Carousel - - Checkout - - Health and Hygiene - - Household - - Periodicals - - All Products - - All Products - - All Products -
      - All Media - - 266,773 - - 225,627.23 - - 19,477.23 - - 163,270.72 - - 42,879.28 - - 565,238.13 - - 131,558 - - 111,777.48 - - 280,226.21 - - 24,457.37 - - 203,094.17 - - 52,674.67 - - 655.55 - - 1,874.82 - - 15,819.73 - - 29,741.49 - - 4,583.08 - - 135,215 - - 113,849.75 - - 285,011.92 -
      +   + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender +
      + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + F + + F + + F + + F + + F + + F + + F + + F + + F + + F + + F + + M + + M + + M +
      + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures +
      + Unit Sales + + Store Cost + + Store Cost + + Store Cost + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Store Sales + + Store Sales + + Store Sales + + Store Sales + + Store Sales + + Store Sales + + Store Sales + + Store Sales + + Unit Sales + + Store Cost + + Store Sales +
      + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product +
      + Promotion Media + + All Products + + All Products + + Drink + + Food + + Non-Consumable + + All Products + + All Products + + All Products + + All Products + + Drink + + Food + + Non-Consumable + + Carousel + + Checkout + + Health and Hygiene + + Household + + Periodicals + + All Products + + All Products + + All Products +
      + All Media + + 266,773 + + 225,627.23 + + 19,477.23 + + 163,270.72 + + 42,879.28 + + 565,238.13 + + 131,558 + + 111,777.48 + + 280,226.21 + + 24,457.37 + + 203,094.17 + + 52,674.67 + + 655.55 + + 1,874.82 + + 15,819.73 + + 29,741.49 + + 4,583.08 + + 135,215 + + 113,849.75 + + 285,011.92 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-columns-true-true-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-columns-true-true-true-result.html index e2ec62d7..d27d5dd2 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-columns-true-true-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-columns-true-true-true-result.html @@ -1,548 +1,548 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender -
      - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender -
      - F - - F - - F - - F - - F - - F - - F - - F - - F - - F - - F - - M - - M - - M -
      - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures -
      - Unit Sales - - Store Cost - - Store Cost - - Store Cost - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Store Sales - - Store Sales - - Store Sales - - Store Sales - - Store Sales - - Store Sales - - Store Sales - - Store Sales - - Unit Sales - - Store Cost - - Store Sales -
      - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product -
      - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products -
      - Promotion Media - - Drink - - Food - - Non-Consumable - - Drink - - Food - - Non-Consumable - - Non-Consumable - - Non-Consumable - - Non-Consumable - - Non-Consumable - - Non-Consumable -
      - (All) - - Carousel - - Checkout - - Health and Hygiene - - Household - - Periodicals -
      - All Media - - 266,773 - - 225,627.23 - - 19,477.23 - - 163,270.72 - - 42,879.28 - - 565,238.13 - - 131,558 - - 111,777.48 - - 280,226.21 - - 24,457.37 - - 203,094.17 - - 52,674.67 - - 655.55 - - 1,874.82 - - 15,819.73 - - 29,741.49 - - 4,583.08 - - 135,215 - - 113,849.75 - - 285,011.92 -
      +   + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender +
      + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender +
      + F + + F + + F + + F + + F + + F + + F + + F + + F + + F + + F + + M + + M + + M +
      + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures +
      + Unit Sales + + Store Cost + + Store Cost + + Store Cost + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Store Sales + + Store Sales + + Store Sales + + Store Sales + + Store Sales + + Store Sales + + Store Sales + + Store Sales + + Unit Sales + + Store Cost + + Store Sales +
      + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product +
      + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products +
      + Promotion Media + + Drink + + Food + + Non-Consumable + + Drink + + Food + + Non-Consumable + + Non-Consumable + + Non-Consumable + + Non-Consumable + + Non-Consumable + + Non-Consumable +
      + (All) + + Carousel + + Checkout + + Health and Hygiene + + Household + + Periodicals +
      + All Media + + 266,773 + + 225,627.23 + + 19,477.23 + + 163,270.72 + + 42,879.28 + + 565,238.13 + + 131,558 + + 111,777.48 + + 280,226.21 + + 24,457.37 + + 203,094.17 + + 52,674.67 + + 655.55 + + 1,874.82 + + 15,819.73 + + 29,741.49 + + 4,583.08 + + 135,215 + + 113,849.75 + + 285,011.92 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-member-properties-false-false-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-member-properties-false-false-false-result.html index 5ba6e3ba..537e757b 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-member-properties-false-false-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-member-properties-false-false-false-result.html @@ -1,1041 +1,1041 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - All Products -
      - Unit Sales - - Store Cost - - Store Sales -
      - All Stores - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - - 266,773 - - 225,627.23 - - 565,238.13 -
      - Canada - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - -   - -   - -   -
      - BC - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - -   - -   - -   -
      - Vancouver - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - -   - -   - -   -
      - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - All Media - -   - -   - -   -
      - Bulk Mail - -   - -   - -   -
      - Cash Register Handout - -   - -   - -   -
      - Daily Paper - -   - -   - -   -
      - Daily Paper, Radio - -   - -   - -   -
      - Daily Paper, Radio, TV - -   - -   - -   -
      - In-Store Coupon - -   - -   - -   -
      - No Media - -   - -   - -   -
      - Product Attachment - -   - -   - -   -
      - Radio - -   - -   - -   -
      - Street Handout - -   - -   - -   -
      - Sunday Paper - -   - -   - -   -
      - Sunday Paper, Radio - -   - -   - -   -
      - Sunday Paper, Radio, TV - -   - -   - -   -
      - TV - -   - -   - -   -
      - Victoria - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - -   - -   - -   -
      - Store 20 - - Mid-Size Grocery - - Cobb - - 34452 - - 27463 - - 4193 - - 2795 - - 1 - - 3706 Marvelle Ln - - All Media - -   - -   - -   -
      - Mexico - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - -   - -   - -   -
      - USA - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - - 266,773 - - 225,627.23 - - 565,238.13 -
      - CA - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - - 74,748 - - 63,530.43 - - 159,167.84 -
      - Alameda - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - -   - -   - -   -
      - HQ - - HeadQuarters - -   - -   - -   - -   - -   - - 0 - - 1 Alameda Way - - All Media - -   - -   - -   -
      - Beverly Hills - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - - 21,333 - - 18,266.44 - - 45,750.24 -
      - Store 6 - - Gourmet Supermarket - - Maris - - 23688 - - 15337 - - 5011 - - 3340 - - 1 - - 5495 Mitchell Canyon Road - - All Media - - 21,333 - - 18,266.44 - - 45,750.24 -
      - Los Angeles - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - - 25,663 - - 21,771.54 - - 54,545.28 -
      - San Diego - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - - 25,635 - - 21,713.53 - - 54,431.14 -
      - Store 24 - - Supermarket - - Byrd - -   - -   - -   - -   - - 1 - - 2342 Waltham St. - - All Media - - 25,635 - - 21,713.53 - - 54,431.14 -
      - San Francisco - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - - 2,117 - - 1,778.92 - - 4,441.18 -
      - OR - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - - 67,659 - - 56,772.50 - - 142,277.07 -
      - WA - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - - 124,366 - - 105,324.31 - - 263,793.22 -
      +   + + All Products +
      + Unit Sales + + Store Cost + + Store Sales +
      + All Stores + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + + 266,773 + + 225,627.23 + + 565,238.13 +
      + Canada + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + +   + +   + +   +
      + BC + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + +   + +   + +   +
      + Vancouver + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + +   + +   + +   +
      + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + All Media + +   + +   + +   +
      + Bulk Mail + +   + +   + +   +
      + Cash Register Handout + +   + +   + +   +
      + Daily Paper + +   + +   + +   +
      + Daily Paper, Radio + +   + +   + +   +
      + Daily Paper, Radio, TV + +   + +   + +   +
      + In-Store Coupon + +   + +   + +   +
      + No Media + +   + +   + +   +
      + Product Attachment + +   + +   + +   +
      + Radio + +   + +   + +   +
      + Street Handout + +   + +   + +   +
      + Sunday Paper + +   + +   + +   +
      + Sunday Paper, Radio + +   + +   + +   +
      + Sunday Paper, Radio, TV + +   + +   + +   +
      + TV + +   + +   + +   +
      + Victoria + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + +   + +   + +   +
      + Store 20 + + Mid-Size Grocery + + Cobb + + 34452 + + 27463 + + 4193 + + 2795 + + 1 + + 3706 Marvelle Ln + + All Media + +   + +   + +   +
      + Mexico + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + +   + +   + +   +
      + USA + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + + 266,773 + + 225,627.23 + + 565,238.13 +
      + CA + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + + 74,748 + + 63,530.43 + + 159,167.84 +
      + Alameda + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + +   + +   + +   +
      + HQ + + HeadQuarters + +   + +   + +   + +   + +   + + 0 + + 1 Alameda Way + + All Media + +   + +   + +   +
      + Beverly Hills + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + + 21,333 + + 18,266.44 + + 45,750.24 +
      + Store 6 + + Gourmet Supermarket + + Maris + + 23688 + + 15337 + + 5011 + + 3340 + + 1 + + 5495 Mitchell Canyon Road + + All Media + + 21,333 + + 18,266.44 + + 45,750.24 +
      + Los Angeles + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + + 25,663 + + 21,771.54 + + 54,545.28 +
      + San Diego + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + + 25,635 + + 21,713.53 + + 54,431.14 +
      + Store 24 + + Supermarket + + Byrd + +   + +   + +   + +   + + 1 + + 2342 Waltham St. + + All Media + + 25,635 + + 21,713.53 + + 54,431.14 +
      + San Francisco + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + + 2,117 + + 1,778.92 + + 4,441.18 +
      + OR + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + + 67,659 + + 56,772.50 + + 142,277.07 +
      + WA + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + + 124,366 + + 105,324.31 + + 263,793.22 +
      \ No newline at end of file diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-member-properties-false-false-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-member-properties-false-false-true-result.html index 5904507c..c6892af5 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-member-properties-false-false-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-member-properties-false-false-true-result.html @@ -1,714 +1,714 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - All Products -
      - Unit Sales - - Store Cost - - Store Sales -
      - All Stores - - All Media - - 266,773 - - 225,627.23 - - 565,238.13 -
      - All Stores - - Canada - - All Media - -   - -   - -   -
      - Canada - - BC - - All Media - -   - -   - -   -
      - BC - - Vancouver - - All Media - -   - -   - -   -
      - Vancouver - - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - All Media - -   - -   - -   -
      - All Media - - Bulk Mail - -   - -   - -   -
      - Cash Register Handout - -   - -   - -   -
      - Daily Paper - -   - -   - -   -
      - Daily Paper, Radio - -   - -   - -   -
      - Daily Paper, Radio, TV - -   - -   - -   -
      - In-Store Coupon - -   - -   - -   -
      - No Media - -   - -   - -   -
      - Product Attachment - -   - -   - -   -
      - Radio - -   - -   - -   -
      - Street Handout - -   - -   - -   -
      - Sunday Paper - -   - -   - -   -
      - Sunday Paper, Radio - -   - -   - -   -
      - Sunday Paper, Radio, TV - -   - -   - -   -
      - TV - -   - -   - -   -
      - Victoria - - All Media - -   - -   - -   -
      - Victoria - - Store 20 - - Mid-Size Grocery - - Cobb - - 34452 - - 27463 - - 4193 - - 2795 - - 1 - - 3706 Marvelle Ln - - All Media - -   - -   - -   -
      - Mexico - - All Media - -   - -   - -   -
      - USA - - All Media - - 266,773 - - 225,627.23 - - 565,238.13 -
      - USA - - CA - - All Media - - 74,748 - - 63,530.43 - - 159,167.84 -
      - CA - - Alameda - - All Media - -   - -   - -   -
      - Alameda - - HQ - - HeadQuarters - -   - -   - -   - -   - -   - - 0 - - 1 Alameda Way - - All Media - -   - -   - -   -
      - Beverly Hills - - All Media - - 21,333 - - 18,266.44 - - 45,750.24 -
      - Beverly Hills - - Store 6 - - Gourmet Supermarket - - Maris - - 23688 - - 15337 - - 5011 - - 3340 - - 1 - - 5495 Mitchell Canyon Road - - All Media - - 21,333 - - 18,266.44 - - 45,750.24 -
      - Los Angeles - - All Media - - 25,663 - - 21,771.54 - - 54,545.28 -
      - San Diego - - All Media - - 25,635 - - 21,713.53 - - 54,431.14 -
      - San Diego - - Store 24 - - Supermarket - - Byrd - -   - -   - -   - -   - - 1 - - 2342 Waltham St. - - All Media - - 25,635 - - 21,713.53 - - 54,431.14 -
      - San Francisco - - All Media - - 2,117 - - 1,778.92 - - 4,441.18 -
      - OR - - All Media - - 67,659 - - 56,772.50 - - 142,277.07 -
      - WA - - All Media - - 124,366 - - 105,324.31 - - 263,793.22 -
      +   + + All Products +
      + Unit Sales + + Store Cost + + Store Sales +
      + All Stores + + All Media + + 266,773 + + 225,627.23 + + 565,238.13 +
      + All Stores + + Canada + + All Media + +   + +   + +   +
      + Canada + + BC + + All Media + +   + +   + +   +
      + BC + + Vancouver + + All Media + +   + +   + +   +
      + Vancouver + + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + All Media + +   + +   + +   +
      + All Media + + Bulk Mail + +   + +   + +   +
      + Cash Register Handout + +   + +   + +   +
      + Daily Paper + +   + +   + +   +
      + Daily Paper, Radio + +   + +   + +   +
      + Daily Paper, Radio, TV + +   + +   + +   +
      + In-Store Coupon + +   + +   + +   +
      + No Media + +   + +   + +   +
      + Product Attachment + +   + +   + +   +
      + Radio + +   + +   + +   +
      + Street Handout + +   + +   + +   +
      + Sunday Paper + +   + +   + +   +
      + Sunday Paper, Radio + +   + +   + +   +
      + Sunday Paper, Radio, TV + +   + +   + +   +
      + TV + +   + +   + +   +
      + Victoria + + All Media + +   + +   + +   +
      + Victoria + + Store 20 + + Mid-Size Grocery + + Cobb + + 34452 + + 27463 + + 4193 + + 2795 + + 1 + + 3706 Marvelle Ln + + All Media + +   + +   + +   +
      + Mexico + + All Media + +   + +   + +   +
      + USA + + All Media + + 266,773 + + 225,627.23 + + 565,238.13 +
      + USA + + CA + + All Media + + 74,748 + + 63,530.43 + + 159,167.84 +
      + CA + + Alameda + + All Media + +   + +   + +   +
      + Alameda + + HQ + + HeadQuarters + +   + +   + +   + +   + +   + + 0 + + 1 Alameda Way + + All Media + +   + +   + +   +
      + Beverly Hills + + All Media + + 21,333 + + 18,266.44 + + 45,750.24 +
      + Beverly Hills + + Store 6 + + Gourmet Supermarket + + Maris + + 23688 + + 15337 + + 5011 + + 3340 + + 1 + + 5495 Mitchell Canyon Road + + All Media + + 21,333 + + 18,266.44 + + 45,750.24 +
      + Los Angeles + + All Media + + 25,663 + + 21,771.54 + + 54,545.28 +
      + San Diego + + All Media + + 25,635 + + 21,713.53 + + 54,431.14 +
      + San Diego + + Store 24 + + Supermarket + + Byrd + +   + +   + +   + +   + + 1 + + 2342 Waltham St. + + All Media + + 25,635 + + 21,713.53 + + 54,431.14 +
      + San Francisco + + All Media + + 2,117 + + 1,778.92 + + 4,441.18 +
      + OR + + All Media + + 67,659 + + 56,772.50 + + 142,277.07 +
      + WA + + All Media + + 124,366 + + 105,324.31 + + 263,793.22 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-member-properties-false-true-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-member-properties-false-true-false-result.html index 68c93ce6..204c0afc 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-member-properties-false-true-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-member-properties-false-true-false-result.html @@ -1,1081 +1,1081 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Product -
      - All Products -
      - Measures -
      - Store - - Store Type - - Store Manager - - Store Sqft - - Grocery Sqft - - Frozen Sqft - - Meat Sqft - - Has coffee bar - - Street address - - Promotion Media - - Unit Sales - - Store Cost - - Store Sales -
      - All Stores - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - - 266,773 - - 225,627.23 - - 565,238.13 -
      - Canada - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - -   - -   - -   -
      - BC - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - -   - -   - -   -
      - Vancouver - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - -   - -   - -   -
      - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - All Media - -   - -   - -   -
      - Bulk Mail - -   - -   - -   -
      - Cash Register Handout - -   - -   - -   -
      - Daily Paper - -   - -   - -   -
      - Daily Paper, Radio - -   - -   - -   -
      - Daily Paper, Radio, TV - -   - -   - -   -
      - In-Store Coupon - -   - -   - -   -
      - No Media - -   - -   - -   -
      - Product Attachment - -   - -   - -   -
      - Radio - -   - -   - -   -
      - Street Handout - -   - -   - -   -
      - Sunday Paper - -   - -   - -   -
      - Sunday Paper, Radio - -   - -   - -   -
      - Sunday Paper, Radio, TV - -   - -   - -   -
      - TV - -   - -   - -   -
      - Victoria - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - -   - -   - -   -
      - Store 20 - - Mid-Size Grocery - - Cobb - - 34452 - - 27463 - - 4193 - - 2795 - - 1 - - 3706 Marvelle Ln - - All Media - -   - -   - -   -
      - Mexico - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - -   - -   - -   -
      - USA - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - - 266,773 - - 225,627.23 - - 565,238.13 -
      - CA - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - - 74,748 - - 63,530.43 - - 159,167.84 -
      - Alameda - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - -   - -   - -   -
      - HQ - - HeadQuarters - -   - -   - -   - -   - -   - - 0 - - 1 Alameda Way - - All Media - -   - -   - -   -
      - Beverly Hills - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - - 21,333 - - 18,266.44 - - 45,750.24 -
      - Store 6 - - Gourmet Supermarket - - Maris - - 23688 - - 15337 - - 5011 - - 3340 - - 1 - - 5495 Mitchell Canyon Road - - All Media - - 21,333 - - 18,266.44 - - 45,750.24 -
      - Los Angeles - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - - 25,663 - - 21,771.54 - - 54,545.28 -
      - San Diego - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - - 25,635 - - 21,713.53 - - 54,431.14 -
      - Store 24 - - Supermarket - - Byrd - -   - -   - -   - -   - - 1 - - 2342 Waltham St. - - All Media - - 25,635 - - 21,713.53 - - 54,431.14 -
      - San Francisco - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - - 2,117 - - 1,778.92 - - 4,441.18 -
      - OR - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - - 67,659 - - 56,772.50 - - 142,277.07 -
      - WA - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - - 124,366 - - 105,324.31 - - 263,793.22 -
      +   + + Product +
      + All Products +
      + Measures +
      + Store + + Store Type + + Store Manager + + Store Sqft + + Grocery Sqft + + Frozen Sqft + + Meat Sqft + + Has coffee bar + + Street address + + Promotion Media + + Unit Sales + + Store Cost + + Store Sales +
      + All Stores + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + + 266,773 + + 225,627.23 + + 565,238.13 +
      + Canada + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + +   + +   + +   +
      + BC + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + +   + +   + +   +
      + Vancouver + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + +   + +   + +   +
      + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + All Media + +   + +   + +   +
      + Bulk Mail + +   + +   + +   +
      + Cash Register Handout + +   + +   + +   +
      + Daily Paper + +   + +   + +   +
      + Daily Paper, Radio + +   + +   + +   +
      + Daily Paper, Radio, TV + +   + +   + +   +
      + In-Store Coupon + +   + +   + +   +
      + No Media + +   + +   + +   +
      + Product Attachment + +   + +   + +   +
      + Radio + +   + +   + +   +
      + Street Handout + +   + +   + +   +
      + Sunday Paper + +   + +   + +   +
      + Sunday Paper, Radio + +   + +   + +   +
      + Sunday Paper, Radio, TV + +   + +   + +   +
      + TV + +   + +   + +   +
      + Victoria + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + +   + +   + +   +
      + Store 20 + + Mid-Size Grocery + + Cobb + + 34452 + + 27463 + + 4193 + + 2795 + + 1 + + 3706 Marvelle Ln + + All Media + +   + +   + +   +
      + Mexico + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + +   + +   + +   +
      + USA + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + + 266,773 + + 225,627.23 + + 565,238.13 +
      + CA + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + + 74,748 + + 63,530.43 + + 159,167.84 +
      + Alameda + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + +   + +   + +   +
      + HQ + + HeadQuarters + +   + +   + +   + +   + +   + + 0 + + 1 Alameda Way + + All Media + +   + +   + +   +
      + Beverly Hills + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + + 21,333 + + 18,266.44 + + 45,750.24 +
      + Store 6 + + Gourmet Supermarket + + Maris + + 23688 + + 15337 + + 5011 + + 3340 + + 1 + + 5495 Mitchell Canyon Road + + All Media + + 21,333 + + 18,266.44 + + 45,750.24 +
      + Los Angeles + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + + 25,663 + + 21,771.54 + + 54,545.28 +
      + San Diego + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + + 25,635 + + 21,713.53 + + 54,431.14 +
      + Store 24 + + Supermarket + + Byrd + +   + +   + +   + +   + + 1 + + 2342 Waltham St. + + All Media + + 25,635 + + 21,713.53 + + 54,431.14 +
      + San Francisco + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + + 2,117 + + 1,778.92 + + 4,441.18 +
      + OR + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + + 67,659 + + 56,772.50 + + 142,277.07 +
      + WA + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + + 124,366 + + 105,324.31 + + 263,793.22 +
      \ No newline at end of file diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-member-properties-false-true-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-member-properties-false-true-true-result.html index 67aec7bb..616786cd 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-member-properties-false-true-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-member-properties-false-true-true-result.html @@ -1,775 +1,775 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Product -
      - All Products -
      - Store - - Promotion Media - - Measures -
      - (All) - - Store Country - - Store State - - Store City - - Store Name - - Store Type - - Store Manager - - Store Sqft - - Grocery Sqft - - Frozen Sqft - - Meat Sqft - - Has coffee bar - - Street address - - (All) - - Media Type - - Unit Sales - - Store Cost - - Store Sales -
      - All Stores - - All Media - - 266,773 - - 225,627.23 - - 565,238.13 -
      - All Stores - - Canada - - All Media - -   - -   - -   -
      - Canada - - BC - - All Media - -   - -   - -   -
      - BC - - Vancouver - - All Media - -   - -   - -   -
      - Vancouver - - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - All Media - -   - -   - -   -
      - All Media - - Bulk Mail - -   - -   - -   -
      - Cash Register Handout - -   - -   - -   -
      - Daily Paper - -   - -   - -   -
      - Daily Paper, Radio - -   - -   - -   -
      - Daily Paper, Radio, TV - -   - -   - -   -
      - In-Store Coupon - -   - -   - -   -
      - No Media - -   - -   - -   -
      - Product Attachment - -   - -   - -   -
      - Radio - -   - -   - -   -
      - Street Handout - -   - -   - -   -
      - Sunday Paper - -   - -   - -   -
      - Sunday Paper, Radio - -   - -   - -   -
      - Sunday Paper, Radio, TV - -   - -   - -   -
      - TV - -   - -   - -   -
      - Victoria - - All Media - -   - -   - -   -
      - Victoria - - Store 20 - - Mid-Size Grocery - - Cobb - - 34452 - - 27463 - - 4193 - - 2795 - - 1 - - 3706 Marvelle Ln - - All Media - -   - -   - -   -
      - Mexico - - All Media - -   - -   - -   -
      - USA - - All Media - - 266,773 - - 225,627.23 - - 565,238.13 -
      - USA - - CA - - All Media - - 74,748 - - 63,530.43 - - 159,167.84 -
      - CA - - Alameda - - All Media - -   - -   - -   -
      - Alameda - - HQ - - HeadQuarters - -   - -   - -   - -   - -   - - 0 - - 1 Alameda Way - - All Media - -   - -   - -   -
      - Beverly Hills - - All Media - - 21,333 - - 18,266.44 - - 45,750.24 -
      - Beverly Hills - - Store 6 - - Gourmet Supermarket - - Maris - - 23688 - - 15337 - - 5011 - - 3340 - - 1 - - 5495 Mitchell Canyon Road - - All Media - - 21,333 - - 18,266.44 - - 45,750.24 -
      - Los Angeles - - All Media - - 25,663 - - 21,771.54 - - 54,545.28 -
      - San Diego - - All Media - - 25,635 - - 21,713.53 - - 54,431.14 -
      - San Diego - - Store 24 - - Supermarket - - Byrd - -   - -   - -   - -   - - 1 - - 2342 Waltham St. - - All Media - - 25,635 - - 21,713.53 - - 54,431.14 -
      - San Francisco - - All Media - - 2,117 - - 1,778.92 - - 4,441.18 -
      - OR - - All Media - - 67,659 - - 56,772.50 - - 142,277.07 -
      - WA - - All Media - - 124,366 - - 105,324.31 - - 263,793.22 -
      +   + + Product +
      + All Products +
      + Store + + Promotion Media + + Measures +
      + (All) + + Store Country + + Store State + + Store City + + Store Name + + Store Type + + Store Manager + + Store Sqft + + Grocery Sqft + + Frozen Sqft + + Meat Sqft + + Has coffee bar + + Street address + + (All) + + Media Type + + Unit Sales + + Store Cost + + Store Sales +
      + All Stores + + All Media + + 266,773 + + 225,627.23 + + 565,238.13 +
      + All Stores + + Canada + + All Media + +   + +   + +   +
      + Canada + + BC + + All Media + +   + +   + +   +
      + BC + + Vancouver + + All Media + +   + +   + +   +
      + Vancouver + + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + All Media + +   + +   + +   +
      + All Media + + Bulk Mail + +   + +   + +   +
      + Cash Register Handout + +   + +   + +   +
      + Daily Paper + +   + +   + +   +
      + Daily Paper, Radio + +   + +   + +   +
      + Daily Paper, Radio, TV + +   + +   + +   +
      + In-Store Coupon + +   + +   + +   +
      + No Media + +   + +   + +   +
      + Product Attachment + +   + +   + +   +
      + Radio + +   + +   + +   +
      + Street Handout + +   + +   + +   +
      + Sunday Paper + +   + +   + +   +
      + Sunday Paper, Radio + +   + +   + +   +
      + Sunday Paper, Radio, TV + +   + +   + +   +
      + TV + +   + +   + +   +
      + Victoria + + All Media + +   + +   + +   +
      + Victoria + + Store 20 + + Mid-Size Grocery + + Cobb + + 34452 + + 27463 + + 4193 + + 2795 + + 1 + + 3706 Marvelle Ln + + All Media + +   + +   + +   +
      + Mexico + + All Media + +   + +   + +   +
      + USA + + All Media + + 266,773 + + 225,627.23 + + 565,238.13 +
      + USA + + CA + + All Media + + 74,748 + + 63,530.43 + + 159,167.84 +
      + CA + + Alameda + + All Media + +   + +   + +   +
      + Alameda + + HQ + + HeadQuarters + +   + +   + +   + +   + +   + + 0 + + 1 Alameda Way + + All Media + +   + +   + +   +
      + Beverly Hills + + All Media + + 21,333 + + 18,266.44 + + 45,750.24 +
      + Beverly Hills + + Store 6 + + Gourmet Supermarket + + Maris + + 23688 + + 15337 + + 5011 + + 3340 + + 1 + + 5495 Mitchell Canyon Road + + All Media + + 21,333 + + 18,266.44 + + 45,750.24 +
      + Los Angeles + + All Media + + 25,663 + + 21,771.54 + + 54,545.28 +
      + San Diego + + All Media + + 25,635 + + 21,713.53 + + 54,431.14 +
      + San Diego + + Store 24 + + Supermarket + + Byrd + +   + +   + +   + +   + + 1 + + 2342 Waltham St. + + All Media + + 25,635 + + 21,713.53 + + 54,431.14 +
      + San Francisco + + All Media + + 2,117 + + 1,778.92 + + 4,441.18 +
      + OR + + All Media + + 67,659 + + 56,772.50 + + 142,277.07 +
      + WA + + All Media + + 124,366 + + 105,324.31 + + 263,793.22 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-member-properties-true-false-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-member-properties-true-false-false-result.html index c8db11ad..c022d603 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-member-properties-true-false-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-member-properties-true-false-false-result.html @@ -1,1425 +1,1425 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - All Products - - All Products - - All Products -
      - Unit Sales - - Store Cost - - Store Sales -
      - All Stores - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - - 266,773 - - 225,627.23 - - 565,238.13 -
      - Canada - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - -   - -   - -   -
      - BC - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - -   - -   - -   -
      - Vancouver - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - -   - -   - -   -
      - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - All Media - -   - -   - -   -
      - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - Bulk Mail - -   - -   - -   -
      - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - Cash Register Handout - -   - -   - -   -
      - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - Daily Paper - -   - -   - -   -
      - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - Daily Paper, Radio - -   - -   - -   -
      - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - Daily Paper, Radio, TV - -   - -   - -   -
      - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - In-Store Coupon - -   - -   - -   -
      - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - No Media - -   - -   - -   -
      - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - Product Attachment - -   - -   - -   -
      - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - Radio - -   - -   - -   -
      - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - Street Handout - -   - -   - -   -
      - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - Sunday Paper - -   - -   - -   -
      - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - Sunday Paper, Radio - -   - -   - -   -
      - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - Sunday Paper, Radio, TV - -   - -   - -   -
      - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - TV - -   - -   - -   -
      - Victoria - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - -   - -   - -   -
      - Store 20 - - Mid-Size Grocery - - Cobb - - 34452 - - 27463 - - 4193 - - 2795 - - 1 - - 3706 Marvelle Ln - - All Media - -   - -   - -   -
      - Mexico - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - -   - -   - -   -
      - USA - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - - 266,773 - - 225,627.23 - - 565,238.13 -
      - CA - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - - 74,748 - - 63,530.43 - - 159,167.84 -
      - Alameda - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - -   - -   - -   -
      - HQ - - HeadQuarters - -   - -   - -   - -   - -   - - 0 - - 1 Alameda Way - - All Media - -   - -   - -   -
      - Beverly Hills - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - - 21,333 - - 18,266.44 - - 45,750.24 -
      - Store 6 - - Gourmet Supermarket - - Maris - - 23688 - - 15337 - - 5011 - - 3340 - - 1 - - 5495 Mitchell Canyon Road - - All Media - - 21,333 - - 18,266.44 - - 45,750.24 -
      - Los Angeles - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - - 25,663 - - 21,771.54 - - 54,545.28 -
      - San Diego - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - - 25,635 - - 21,713.53 - - 54,431.14 -
      - Store 24 - - Supermarket - - Byrd - -   - -   - -   - -   - - 1 - - 2342 Waltham St. - - All Media - - 25,635 - - 21,713.53 - - 54,431.14 -
      - San Francisco - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - - 2,117 - - 1,778.92 - - 4,441.18 -
      - OR - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - - 67,659 - - 56,772.50 - - 142,277.07 -
      - WA - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - - 124,366 - - 105,324.31 - - 263,793.22 -
      +   + + All Products + + All Products + + All Products +
      + Unit Sales + + Store Cost + + Store Sales +
      + All Stores + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + + 266,773 + + 225,627.23 + + 565,238.13 +
      + Canada + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + +   + +   + +   +
      + BC + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + +   + +   + +   +
      + Vancouver + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + +   + +   + +   +
      + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + All Media + +   + +   + +   +
      + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + Bulk Mail + +   + +   + +   +
      + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + Cash Register Handout + +   + +   + +   +
      + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + Daily Paper + +   + +   + +   +
      + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + Daily Paper, Radio + +   + +   + +   +
      + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + Daily Paper, Radio, TV + +   + +   + +   +
      + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + In-Store Coupon + +   + +   + +   +
      + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + No Media + +   + +   + +   +
      + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + Product Attachment + +   + +   + +   +
      + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + Radio + +   + +   + +   +
      + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + Street Handout + +   + +   + +   +
      + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + Sunday Paper + +   + +   + +   +
      + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + Sunday Paper, Radio + +   + +   + +   +
      + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + Sunday Paper, Radio, TV + +   + +   + +   +
      + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + TV + +   + +   + +   +
      + Victoria + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + +   + +   + +   +
      + Store 20 + + Mid-Size Grocery + + Cobb + + 34452 + + 27463 + + 4193 + + 2795 + + 1 + + 3706 Marvelle Ln + + All Media + +   + +   + +   +
      + Mexico + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + +   + +   + +   +
      + USA + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + + 266,773 + + 225,627.23 + + 565,238.13 +
      + CA + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + + 74,748 + + 63,530.43 + + 159,167.84 +
      + Alameda + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + +   + +   + +   +
      + HQ + + HeadQuarters + +   + +   + +   + +   + +   + + 0 + + 1 Alameda Way + + All Media + +   + +   + +   +
      + Beverly Hills + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + + 21,333 + + 18,266.44 + + 45,750.24 +
      + Store 6 + + Gourmet Supermarket + + Maris + + 23688 + + 15337 + + 5011 + + 3340 + + 1 + + 5495 Mitchell Canyon Road + + All Media + + 21,333 + + 18,266.44 + + 45,750.24 +
      + Los Angeles + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + + 25,663 + + 21,771.54 + + 54,545.28 +
      + San Diego + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + + 25,635 + + 21,713.53 + + 54,431.14 +
      + Store 24 + + Supermarket + + Byrd + +   + +   + +   + +   + + 1 + + 2342 Waltham St. + + All Media + + 25,635 + + 21,713.53 + + 54,431.14 +
      + San Francisco + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + + 2,117 + + 1,778.92 + + 4,441.18 +
      + OR + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + + 67,659 + + 56,772.50 + + 142,277.07 +
      + WA + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + + 124,366 + + 105,324.31 + + 263,793.22 +
      \ No newline at end of file diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-member-properties-true-false-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-member-properties-true-false-true-result.html index 5f6f0fbe..69b17f20 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-member-properties-true-false-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-member-properties-true-false-true-result.html @@ -1,1431 +1,1431 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - All Products - - All Products - - All Products -
      - Unit Sales - - Store Cost - - Store Sales -
      - All Stores - - All Media - - 266,773 - - 225,627.23 - - 565,238.13 -
      - All Stores - - Canada - - All Media - -   - -   - -   -
      - All Stores - - Canada - - BC - - All Media - -   - -   - -   -
      - All Stores - - Canada - - BC - - Vancouver - - All Media - -   - -   - -   -
      - All Stores - - Canada - - BC - - Vancouver - - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - All Media - -   - -   - -   -
      - All Stores - - Canada - - BC - - Vancouver - - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - All Media - - Bulk Mail - -   - -   - -   -
      - All Stores - - Canada - - BC - - Vancouver - - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - All Media - - Cash Register Handout - -   - -   - -   -
      - All Stores - - Canada - - BC - - Vancouver - - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - All Media - - Daily Paper - -   - -   - -   -
      - All Stores - - Canada - - BC - - Vancouver - - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - All Media - - Daily Paper, Radio - -   - -   - -   -
      - All Stores - - Canada - - BC - - Vancouver - - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - All Media - - Daily Paper, Radio, TV - -   - -   - -   -
      - All Stores - - Canada - - BC - - Vancouver - - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - All Media - - In-Store Coupon - -   - -   - -   -
      - All Stores - - Canada - - BC - - Vancouver - - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - All Media - - No Media - -   - -   - -   -
      - All Stores - - Canada - - BC - - Vancouver - - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - All Media - - Product Attachment - -   - -   - -   -
      - All Stores - - Canada - - BC - - Vancouver - - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - All Media - - Radio - -   - -   - -   -
      - All Stores - - Canada - - BC - - Vancouver - - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - All Media - - Street Handout - -   - -   - -   -
      - All Stores - - Canada - - BC - - Vancouver - - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - All Media - - Sunday Paper - -   - -   - -   -
      - All Stores - - Canada - - BC - - Vancouver - - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - All Media - - Sunday Paper, Radio - -   - -   - -   -
      - All Stores - - Canada - - BC - - Vancouver - - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - All Media - - Sunday Paper, Radio, TV - -   - -   - -   -
      - All Stores - - Canada - - BC - - Vancouver - - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - All Media - - TV - -   - -   - -   -
      - All Stores - - Canada - - BC - - Victoria - - All Media - -   - -   - -   -
      - All Stores - - Canada - - BC - - Victoria - - Store 20 - - Mid-Size Grocery - - Cobb - - 34452 - - 27463 - - 4193 - - 2795 - - 1 - - 3706 Marvelle Ln - - All Media - -   - -   - -   -
      - All Stores - - Mexico - - All Media - -   - -   - -   -
      - All Stores - - USA - - All Media - - 266,773 - - 225,627.23 - - 565,238.13 -
      - All Stores - - USA - - CA - - All Media - - 74,748 - - 63,530.43 - - 159,167.84 -
      - All Stores - - USA - - CA - - Alameda - - All Media - -   - -   - -   -
      - All Stores - - USA - - CA - - Alameda - - HQ - - HeadQuarters - -   - -   - -   - -   - -   - - 0 - - 1 Alameda Way - - All Media - -   - -   - -   -
      - All Stores - - USA - - CA - - Beverly Hills - - All Media - - 21,333 - - 18,266.44 - - 45,750.24 -
      - All Stores - - USA - - CA - - Beverly Hills - - Store 6 - - Gourmet Supermarket - - Maris - - 23688 - - 15337 - - 5011 - - 3340 - - 1 - - 5495 Mitchell Canyon Road - - All Media - - 21,333 - - 18,266.44 - - 45,750.24 -
      - All Stores - - USA - - CA - - Los Angeles - - All Media - - 25,663 - - 21,771.54 - - 54,545.28 -
      - All Stores - - USA - - CA - - San Diego - - All Media - - 25,635 - - 21,713.53 - - 54,431.14 -
      - All Stores - - USA - - CA - - San Diego - - Store 24 - - Supermarket - - Byrd - -   - -   - -   - -   - - 1 - - 2342 Waltham St. - - All Media - - 25,635 - - 21,713.53 - - 54,431.14 -
      - All Stores - - USA - - CA - - San Francisco - - All Media - - 2,117 - - 1,778.92 - - 4,441.18 -
      - All Stores - - USA - - OR - - All Media - - 67,659 - - 56,772.50 - - 142,277.07 -
      - All Stores - - USA - - WA - - All Media - - 124,366 - - 105,324.31 - - 263,793.22 -
      +   + + All Products + + All Products + + All Products +
      + Unit Sales + + Store Cost + + Store Sales +
      + All Stores + + All Media + + 266,773 + + 225,627.23 + + 565,238.13 +
      + All Stores + + Canada + + All Media + +   + +   + +   +
      + All Stores + + Canada + + BC + + All Media + +   + +   + +   +
      + All Stores + + Canada + + BC + + Vancouver + + All Media + +   + +   + +   +
      + All Stores + + Canada + + BC + + Vancouver + + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + All Media + +   + +   + +   +
      + All Stores + + Canada + + BC + + Vancouver + + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + All Media + + Bulk Mail + +   + +   + +   +
      + All Stores + + Canada + + BC + + Vancouver + + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + All Media + + Cash Register Handout + +   + +   + +   +
      + All Stores + + Canada + + BC + + Vancouver + + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + All Media + + Daily Paper + +   + +   + +   +
      + All Stores + + Canada + + BC + + Vancouver + + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + All Media + + Daily Paper, Radio + +   + +   + +   +
      + All Stores + + Canada + + BC + + Vancouver + + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + All Media + + Daily Paper, Radio, TV + +   + +   + +   +
      + All Stores + + Canada + + BC + + Vancouver + + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + All Media + + In-Store Coupon + +   + +   + +   +
      + All Stores + + Canada + + BC + + Vancouver + + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + All Media + + No Media + +   + +   + +   +
      + All Stores + + Canada + + BC + + Vancouver + + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + All Media + + Product Attachment + +   + +   + +   +
      + All Stores + + Canada + + BC + + Vancouver + + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + All Media + + Radio + +   + +   + +   +
      + All Stores + + Canada + + BC + + Vancouver + + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + All Media + + Street Handout + +   + +   + +   +
      + All Stores + + Canada + + BC + + Vancouver + + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + All Media + + Sunday Paper + +   + +   + +   +
      + All Stores + + Canada + + BC + + Vancouver + + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + All Media + + Sunday Paper, Radio + +   + +   + +   +
      + All Stores + + Canada + + BC + + Vancouver + + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + All Media + + Sunday Paper, Radio, TV + +   + +   + +   +
      + All Stores + + Canada + + BC + + Vancouver + + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + All Media + + TV + +   + +   + +   +
      + All Stores + + Canada + + BC + + Victoria + + All Media + +   + +   + +   +
      + All Stores + + Canada + + BC + + Victoria + + Store 20 + + Mid-Size Grocery + + Cobb + + 34452 + + 27463 + + 4193 + + 2795 + + 1 + + 3706 Marvelle Ln + + All Media + +   + +   + +   +
      + All Stores + + Mexico + + All Media + +   + +   + +   +
      + All Stores + + USA + + All Media + + 266,773 + + 225,627.23 + + 565,238.13 +
      + All Stores + + USA + + CA + + All Media + + 74,748 + + 63,530.43 + + 159,167.84 +
      + All Stores + + USA + + CA + + Alameda + + All Media + +   + +   + +   +
      + All Stores + + USA + + CA + + Alameda + + HQ + + HeadQuarters + +   + +   + +   + +   + +   + + 0 + + 1 Alameda Way + + All Media + +   + +   + +   +
      + All Stores + + USA + + CA + + Beverly Hills + + All Media + + 21,333 + + 18,266.44 + + 45,750.24 +
      + All Stores + + USA + + CA + + Beverly Hills + + Store 6 + + Gourmet Supermarket + + Maris + + 23688 + + 15337 + + 5011 + + 3340 + + 1 + + 5495 Mitchell Canyon Road + + All Media + + 21,333 + + 18,266.44 + + 45,750.24 +
      + All Stores + + USA + + CA + + Los Angeles + + All Media + + 25,663 + + 21,771.54 + + 54,545.28 +
      + All Stores + + USA + + CA + + San Diego + + All Media + + 25,635 + + 21,713.53 + + 54,431.14 +
      + All Stores + + USA + + CA + + San Diego + + Store 24 + + Supermarket + + Byrd + +   + +   + +   + +   + + 1 + + 2342 Waltham St. + + All Media + + 25,635 + + 21,713.53 + + 54,431.14 +
      + All Stores + + USA + + CA + + San Francisco + + All Media + + 2,117 + + 1,778.92 + + 4,441.18 +
      + All Stores + + USA + + OR + + All Media + + 67,659 + + 56,772.50 + + 142,277.07 +
      + All Stores + + USA + + WA + + All Media + + 124,366 + + 105,324.31 + + 263,793.22 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-member-properties-true-true-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-member-properties-true-true-false-result.html index 274e5485..9a8038ec 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-member-properties-true-true-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-member-properties-true-true-false-result.html @@ -1,1477 +1,1477 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Product - - Product - - Product -
      - All Products - - All Products - - All Products -
      - Measures - - Measures - - Measures -
      - Store - - Store Type - - Store Manager - - Store Sqft - - Grocery Sqft - - Frozen Sqft - - Meat Sqft - - Has coffee bar - - Street address - - Promotion Media - - Unit Sales - - Store Cost - - Store Sales -
      - All Stores - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - - 266,773 - - 225,627.23 - - 565,238.13 -
      - Canada - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - -   - -   - -   -
      - BC - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - -   - -   - -   -
      - Vancouver - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - -   - -   - -   -
      - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - All Media - -   - -   - -   -
      - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - Bulk Mail - -   - -   - -   -
      - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - Cash Register Handout - -   - -   - -   -
      - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - Daily Paper - -   - -   - -   -
      - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - Daily Paper, Radio - -   - -   - -   -
      - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - Daily Paper, Radio, TV - -   - -   - -   -
      - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - In-Store Coupon - -   - -   - -   -
      - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - No Media - -   - -   - -   -
      - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - Product Attachment - -   - -   - -   -
      - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - Radio - -   - -   - -   -
      - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - Street Handout - -   - -   - -   -
      - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - Sunday Paper - -   - -   - -   -
      - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - Sunday Paper, Radio - -   - -   - -   -
      - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - Sunday Paper, Radio, TV - -   - -   - -   -
      - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - TV - -   - -   - -   -
      - Victoria - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - -   - -   - -   -
      - Store 20 - - Mid-Size Grocery - - Cobb - - 34452 - - 27463 - - 4193 - - 2795 - - 1 - - 3706 Marvelle Ln - - All Media - -   - -   - -   -
      - Mexico - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - -   - -   - -   -
      - USA - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - - 266,773 - - 225,627.23 - - 565,238.13 -
      - CA - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - - 74,748 - - 63,530.43 - - 159,167.84 -
      - Alameda - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - -   - -   - -   -
      - HQ - - HeadQuarters - -   - -   - -   - -   - -   - - 0 - - 1 Alameda Way - - All Media - -   - -   - -   -
      - Beverly Hills - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - - 21,333 - - 18,266.44 - - 45,750.24 -
      - Store 6 - - Gourmet Supermarket - - Maris - - 23688 - - 15337 - - 5011 - - 3340 - - 1 - - 5495 Mitchell Canyon Road - - All Media - - 21,333 - - 18,266.44 - - 45,750.24 -
      - Los Angeles - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - - 25,663 - - 21,771.54 - - 54,545.28 -
      - San Diego - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - - 25,635 - - 21,713.53 - - 54,431.14 -
      - Store 24 - - Supermarket - - Byrd - -   - -   - -   - -   - - 1 - - 2342 Waltham St. - - All Media - - 25,635 - - 21,713.53 - - 54,431.14 -
      - San Francisco - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - - 2,117 - - 1,778.92 - - 4,441.18 -
      - OR - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - - 67,659 - - 56,772.50 - - 142,277.07 -
      - WA - -   - -   - -   - -   - -   - -   - -   - -   - - All Media - - 124,366 - - 105,324.31 - - 263,793.22 -
      +   + + Product + + Product + + Product +
      + All Products + + All Products + + All Products +
      + Measures + + Measures + + Measures +
      + Store + + Store Type + + Store Manager + + Store Sqft + + Grocery Sqft + + Frozen Sqft + + Meat Sqft + + Has coffee bar + + Street address + + Promotion Media + + Unit Sales + + Store Cost + + Store Sales +
      + All Stores + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + + 266,773 + + 225,627.23 + + 565,238.13 +
      + Canada + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + +   + +   + +   +
      + BC + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + +   + +   + +   +
      + Vancouver + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + +   + +   + +   +
      + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + All Media + +   + +   + +   +
      + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + Bulk Mail + +   + +   + +   +
      + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + Cash Register Handout + +   + +   + +   +
      + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + Daily Paper + +   + +   + +   +
      + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + Daily Paper, Radio + +   + +   + +   +
      + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + Daily Paper, Radio, TV + +   + +   + +   +
      + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + In-Store Coupon + +   + +   + +   +
      + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + No Media + +   + +   + +   +
      + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + Product Attachment + +   + +   + +   +
      + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + Radio + +   + +   + +   +
      + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + Street Handout + +   + +   + +   +
      + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + Sunday Paper + +   + +   + +   +
      + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + Sunday Paper, Radio + +   + +   + +   +
      + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + Sunday Paper, Radio, TV + +   + +   + +   +
      + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + TV + +   + +   + +   +
      + Victoria + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + +   + +   + +   +
      + Store 20 + + Mid-Size Grocery + + Cobb + + 34452 + + 27463 + + 4193 + + 2795 + + 1 + + 3706 Marvelle Ln + + All Media + +   + +   + +   +
      + Mexico + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + +   + +   + +   +
      + USA + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + + 266,773 + + 225,627.23 + + 565,238.13 +
      + CA + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + + 74,748 + + 63,530.43 + + 159,167.84 +
      + Alameda + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + +   + +   + +   +
      + HQ + + HeadQuarters + +   + +   + +   + +   + +   + + 0 + + 1 Alameda Way + + All Media + +   + +   + +   +
      + Beverly Hills + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + + 21,333 + + 18,266.44 + + 45,750.24 +
      + Store 6 + + Gourmet Supermarket + + Maris + + 23688 + + 15337 + + 5011 + + 3340 + + 1 + + 5495 Mitchell Canyon Road + + All Media + + 21,333 + + 18,266.44 + + 45,750.24 +
      + Los Angeles + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + + 25,663 + + 21,771.54 + + 54,545.28 +
      + San Diego + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + + 25,635 + + 21,713.53 + + 54,431.14 +
      + Store 24 + + Supermarket + + Byrd + +   + +   + +   + +   + + 1 + + 2342 Waltham St. + + All Media + + 25,635 + + 21,713.53 + + 54,431.14 +
      + San Francisco + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + + 2,117 + + 1,778.92 + + 4,441.18 +
      + OR + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + + 67,659 + + 56,772.50 + + 142,277.07 +
      + WA + +   + +   + +   + +   + +   + +   + +   + +   + + All Media + + 124,366 + + 105,324.31 + + 263,793.22 +
      \ No newline at end of file diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-member-properties-true-true-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-member-properties-true-true-true-result.html index 4cdb5163..536bcda1 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-member-properties-true-true-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/complex-member-properties-true-true-true-result.html @@ -1,1504 +1,1504 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Product - - Product - - Product -
      - All Products - - All Products - - All Products -
      - Store - - Promotion Media - - Measures - - Measures - - Measures -
      - (All) - - Store Country - - Store State - - Store City - - Store Name - - Store Type - - Store Manager - - Store Sqft - - Grocery Sqft - - Frozen Sqft - - Meat Sqft - - Has coffee bar - - Street address - - (All) - - Media Type - - Unit Sales - - Store Cost - - Store Sales -
      - All Stores - - All Media - - 266,773 - - 225,627.23 - - 565,238.13 -
      - All Stores - - Canada - - All Media - -   - -   - -   -
      - All Stores - - Canada - - BC - - All Media - -   - -   - -   -
      - All Stores - - Canada - - BC - - Vancouver - - All Media - -   - -   - -   -
      - All Stores - - Canada - - BC - - Vancouver - - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - All Media - -   - -   - -   -
      - All Stores - - Canada - - BC - - Vancouver - - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - All Media - - Bulk Mail - -   - -   - -   -
      - All Stores - - Canada - - BC - - Vancouver - - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - All Media - - Cash Register Handout - -   - -   - -   -
      - All Stores - - Canada - - BC - - Vancouver - - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - All Media - - Daily Paper - -   - -   - -   -
      - All Stores - - Canada - - BC - - Vancouver - - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - All Media - - Daily Paper, Radio - -   - -   - -   -
      - All Stores - - Canada - - BC - - Vancouver - - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - All Media - - Daily Paper, Radio, TV - -   - -   - -   -
      - All Stores - - Canada - - BC - - Vancouver - - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - All Media - - In-Store Coupon - -   - -   - -   -
      - All Stores - - Canada - - BC - - Vancouver - - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - All Media - - No Media - -   - -   - -   -
      - All Stores - - Canada - - BC - - Vancouver - - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - All Media - - Product Attachment - -   - -   - -   -
      - All Stores - - Canada - - BC - - Vancouver - - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - All Media - - Radio - -   - -   - -   -
      - All Stores - - Canada - - BC - - Vancouver - - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - All Media - - Street Handout - -   - -   - -   -
      - All Stores - - Canada - - BC - - Vancouver - - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - All Media - - Sunday Paper - -   - -   - -   -
      - All Stores - - Canada - - BC - - Vancouver - - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - All Media - - Sunday Paper, Radio - -   - -   - -   -
      - All Stores - - Canada - - BC - - Vancouver - - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - All Media - - Sunday Paper, Radio, TV - -   - -   - -   -
      - All Stores - - Canada - - BC - - Vancouver - - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - - All Media - - TV - -   - -   - -   -
      - All Stores - - Canada - - BC - - Victoria - - All Media - -   - -   - -   -
      - All Stores - - Canada - - BC - - Victoria - - Store 20 - - Mid-Size Grocery - - Cobb - - 34452 - - 27463 - - 4193 - - 2795 - - 1 - - 3706 Marvelle Ln - - All Media - -   - -   - -   -
      - All Stores - - Mexico - - All Media - -   - -   - -   -
      - All Stores - - USA - - All Media - - 266,773 - - 225,627.23 - - 565,238.13 -
      - All Stores - - USA - - CA - - All Media - - 74,748 - - 63,530.43 - - 159,167.84 -
      - All Stores - - USA - - CA - - Alameda - - All Media - -   - -   - -   -
      - All Stores - - USA - - CA - - Alameda - - HQ - - HeadQuarters - -   - -   - -   - -   - -   - - 0 - - 1 Alameda Way - - All Media - -   - -   - -   -
      - All Stores - - USA - - CA - - Beverly Hills - - All Media - - 21,333 - - 18,266.44 - - 45,750.24 -
      - All Stores - - USA - - CA - - Beverly Hills - - Store 6 - - Gourmet Supermarket - - Maris - - 23688 - - 15337 - - 5011 - - 3340 - - 1 - - 5495 Mitchell Canyon Road - - All Media - - 21,333 - - 18,266.44 - - 45,750.24 -
      - All Stores - - USA - - CA - - Los Angeles - - All Media - - 25,663 - - 21,771.54 - - 54,545.28 -
      - All Stores - - USA - - CA - - San Diego - - All Media - - 25,635 - - 21,713.53 - - 54,431.14 -
      - All Stores - - USA - - CA - - San Diego - - Store 24 - - Supermarket - - Byrd - -   - -   - -   - -   - - 1 - - 2342 Waltham St. - - All Media - - 25,635 - - 21,713.53 - - 54,431.14 -
      - All Stores - - USA - - CA - - San Francisco - - All Media - - 2,117 - - 1,778.92 - - 4,441.18 -
      - All Stores - - USA - - OR - - All Media - - 67,659 - - 56,772.50 - - 142,277.07 -
      - All Stores - - USA - - WA - - All Media - - 124,366 - - 105,324.31 - - 263,793.22 -
      +   + + Product + + Product + + Product +
      + All Products + + All Products + + All Products +
      + Store + + Promotion Media + + Measures + + Measures + + Measures +
      + (All) + + Store Country + + Store State + + Store City + + Store Name + + Store Type + + Store Manager + + Store Sqft + + Grocery Sqft + + Frozen Sqft + + Meat Sqft + + Has coffee bar + + Street address + + (All) + + Media Type + + Unit Sales + + Store Cost + + Store Sales +
      + All Stores + + All Media + + 266,773 + + 225,627.23 + + 565,238.13 +
      + All Stores + + Canada + + All Media + +   + +   + +   +
      + All Stores + + Canada + + BC + + All Media + +   + +   + +   +
      + All Stores + + Canada + + BC + + Vancouver + + All Media + +   + +   + +   +
      + All Stores + + Canada + + BC + + Vancouver + + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + All Media + +   + +   + +   +
      + All Stores + + Canada + + BC + + Vancouver + + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + All Media + + Bulk Mail + +   + +   + +   +
      + All Stores + + Canada + + BC + + Vancouver + + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + All Media + + Cash Register Handout + +   + +   + +   +
      + All Stores + + Canada + + BC + + Vancouver + + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + All Media + + Daily Paper + +   + +   + +   +
      + All Stores + + Canada + + BC + + Vancouver + + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + All Media + + Daily Paper, Radio + +   + +   + +   +
      + All Stores + + Canada + + BC + + Vancouver + + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + All Media + + Daily Paper, Radio, TV + +   + +   + +   +
      + All Stores + + Canada + + BC + + Vancouver + + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + All Media + + In-Store Coupon + +   + +   + +   +
      + All Stores + + Canada + + BC + + Vancouver + + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + All Media + + No Media + +   + +   + +   +
      + All Stores + + Canada + + BC + + Vancouver + + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + All Media + + Product Attachment + +   + +   + +   +
      + All Stores + + Canada + + BC + + Vancouver + + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + All Media + + Radio + +   + +   + +   +
      + All Stores + + Canada + + BC + + Vancouver + + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + All Media + + Street Handout + +   + +   + +   +
      + All Stores + + Canada + + BC + + Vancouver + + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + All Media + + Sunday Paper + +   + +   + +   +
      + All Stores + + Canada + + BC + + Vancouver + + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + All Media + + Sunday Paper, Radio + +   + +   + +   +
      + All Stores + + Canada + + BC + + Vancouver + + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + All Media + + Sunday Paper, Radio, TV + +   + +   + +   +
      + All Stores + + Canada + + BC + + Vancouver + + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + + All Media + + TV + +   + +   + +   +
      + All Stores + + Canada + + BC + + Victoria + + All Media + +   + +   + +   +
      + All Stores + + Canada + + BC + + Victoria + + Store 20 + + Mid-Size Grocery + + Cobb + + 34452 + + 27463 + + 4193 + + 2795 + + 1 + + 3706 Marvelle Ln + + All Media + +   + +   + +   +
      + All Stores + + Mexico + + All Media + +   + +   + +   +
      + All Stores + + USA + + All Media + + 266,773 + + 225,627.23 + + 565,238.13 +
      + All Stores + + USA + + CA + + All Media + + 74,748 + + 63,530.43 + + 159,167.84 +
      + All Stores + + USA + + CA + + Alameda + + All Media + +   + +   + +   +
      + All Stores + + USA + + CA + + Alameda + + HQ + + HeadQuarters + +   + +   + +   + +   + +   + + 0 + + 1 Alameda Way + + All Media + +   + +   + +   +
      + All Stores + + USA + + CA + + Beverly Hills + + All Media + + 21,333 + + 18,266.44 + + 45,750.24 +
      + All Stores + + USA + + CA + + Beverly Hills + + Store 6 + + Gourmet Supermarket + + Maris + + 23688 + + 15337 + + 5011 + + 3340 + + 1 + + 5495 Mitchell Canyon Road + + All Media + + 21,333 + + 18,266.44 + + 45,750.24 +
      + All Stores + + USA + + CA + + Los Angeles + + All Media + + 25,663 + + 21,771.54 + + 54,545.28 +
      + All Stores + + USA + + CA + + San Diego + + All Media + + 25,635 + + 21,713.53 + + 54,431.14 +
      + All Stores + + USA + + CA + + San Diego + + Store 24 + + Supermarket + + Byrd + +   + +   + +   + +   + + 1 + + 2342 Waltham St. + + All Media + + 25,635 + + 21,713.53 + + 54,431.14 +
      + All Stores + + USA + + CA + + San Francisco + + All Media + + 2,117 + + 1,778.92 + + 4,441.18 +
      + All Stores + + USA + + OR + + All Media + + 67,659 + + 56,772.50 + + 142,277.07 +
      + All Stores + + USA + + WA + + All Media + + 124,366 + + 105,324.31 + + 263,793.22 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/insane-rows-false-false-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/insane-rows-false-false-false-result.html index 2534f280..88baed6d 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/insane-rows-false-false-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/insane-rows-false-false-false-result.html @@ -1,6743 +1,6743 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - All Products - - All Gender - - 266,773 - - 225,627.23 - - 565,238.13 -
      - Drink - - All Gender - - 24,597 - - 19,477.23 - - 48,836.21 -
      - Food - - All Gender - - 191,940 - - 163,270.72 - - 409,035.59 -
      - Baked Goods - - All Gender - - 7,870 - - 6,564.09 - - 16,455.43 -
      - Baking Goods - - All Gender - - 20,245 - - 15,370.61 - - 38,670.41 -
      - Baking Goods - - All Gender - - 8,357 - - 6,123.32 - - 15,446.69 -
      - F - - 4,005 - - 2,907.70 - - 7,313.61 -
      - M - - 4,352 - - 3,215.62 - - 8,133.08 -
      - Jams and Jellies - - All Gender - - 11,888 - - 9,247.29 - - 23,223.72 -
      - Jam - - All Gender - - 2,556 - - 2,132.27 - - 5,401.81 -
      - Jelly - - All Gender - - 2,565 - - 1,830.04 - - 4,609.61 -
      - F - - 1,309 - - 956.94 - - 2,414.94 -
      - M - - 1,256 - - 873.10 - - 2,194.67 -
      - Peanut Butter - - All Gender - - 2,667 - - 2,097.37 - - 5,231.08 -
      - BBB Best - - All Gender - - 556 - - 424.38 - - 1,055.72 -
      - F - - 271 - - 201.08 - - 500.39 -
      - M - - 285 - - 223.30 - - 555.33 -
      - BBB Best Chunky Peanut Butter - - All Gender - - 188 - - 147.32 - - 370.36 -
      - F - - 107 - - 85.81 - - 210.79 -
      - M - - 81 - - 61.50 - - 159.57 -
      - BBB Best Creamy Peanut Butter - - All Gender - - 201 - - 87.86 - - 221.10 -
      - F - - 99 - - 43.35 - - 108.90 -
      - M - - 102 - - 44.51 - - 112.20 -
      - BBB Best Extra Chunky Peanut Butter - - All Gender - - 167 - - 189.21 - - 464.26 -
      - F - - 65 - - 71.92 - - 180.70 -
      - M - - 102 - - 117.29 - - 283.56 -
      - CDR - - All Gender - - 545 - - 538.88 - - 1,326.30 -
      - Landslide - - All Gender - - 531 - - 256.16 - - 635.29 -
      - Plato - - All Gender - - 520 - - 447.73 - - 1,132.16 -
      - Super - - All Gender - - 515 - - 430.21 - - 1,081.61 -
      - Preserves - - All Gender - - 4,100 - - 3,187.61 - - 7,981.22 -
      - F - - 1,946 - - 1,472.42 - - 3,717.80 -
      - M - - 2,154 - - 1,715.19 - - 4,263.42 -
      - Breakfast Foods - - All Gender - - 3,317 - - 2,756.80 - - 6,941.46 -
      - Canned Foods - - All Gender - - 19,026 - - 15,894.53 - - 39,774.34 -
      - Canned Anchovies - - All Gender - - 900 - - 913.88 - - 2,296.38 -
      - Canned Clams - - All Gender - - 882 - - 759.80 - - 1,912.68 -
      - Clams - - All Gender - - 882 - - 759.80 - - 1,912.68 -
      - Better - - All Gender - - 189 - - 151.14 - - 398.79 -
      - Blue Label - - All Gender - - 165 - - 112.82 - - 278.85 -
      - Bravo - - All Gender - - 184 - - 280.70 - - 708.40 -
      - Just Right - - All Gender - - 177 - - 161.96 - - 394.71 -
      - Pleasant - - All Gender - - 167 - - 53.17 - - 131.93 -
      - Canned Oysters - - All Gender - - 708 - - 571.50 - - 1,442.77 -
      - Canned Sardines - - All Gender - - 819 - - 537.59 - - 1,357.80 -
      - Canned Shrimp - - All Gender - - 804 - - 858.39 - - 2,146.49 -
      - Canned Soup - - All Gender - - 8,006 - - 6,408.29 - - 15,966.10 -
      - Canned Tuna - - All Gender - - 1,710 - - 1,288.52 - - 3,210.76 -
      - Vegetables - - All Gender - - 5,197 - - 4,556.57 - - 11,441.36 -
      - Canned Products - - All Gender - - 1,812 - - 1,317.13 - - 3,314.52 -
      - Dairy - - All Gender - - 12,885 - - 12,228.85 - - 30,508.85 -
      - Deli - - All Gender - - 12,037 - - 10,108.87 - - 25,318.93 -
      - Meat - - All Gender - - 9,433 - - 8,215.81 - - 20,616.29 -
      - Bologna - - All Gender - - 2,588 - - 2,340.24 - - 5,859.95 -
      - Deli Meats - - All Gender - - 3,339 - - 2,851.18 - - 7,191.24 -
      - F - - 1,653 - - 1,414.49 - - 3,579.34 -
      - M - - 1,686 - - 1,436.69 - - 3,611.90 -
      - Fresh Chicken - - All Gender - - 878 - - 842.85 - - 2,091.52 -
      - Hot Dogs - - All Gender - - 2,628 - - 2,181.55 - - 5,473.58 -
      - Side Dishes - - All Gender - - 2,604 - - 1,893.06 - - 4,702.64 -
      - Eggs - - All Gender - - 4,132 - - 3,684.90 - - 9,200.76 -
      - Frozen Foods - - All Gender - - 26,655 - - 22,030.66 - - 55,207.50 -
      - Meat - - All Gender - - 1,714 - - 1,465.42 - - 3,669.89 -
      - Produce - - All Gender - - 37,792 - - 32,831.33 - - 82,248.42 -
      - Seafood - - All Gender - - 1,764 - - 1,520.70 - - 3,809.14 -
      - Snack Foods - - All Gender - - 30,545 - - 26,963.34 - - 67,609.82 -
      - Snacks - - All Gender - - 6,884 - - 5,827.58 - - 14,550.05 -
      - Starchy Foods - - All Gender - - 5,262 - - 4,705.91 - - 11,756.07 -
      - Non-Consumable - - All Gender - - 50,236 - - 42,879.28 - - 107,366.33 -
      - Carousel - - All Gender - - 841 - - 595.97 - - 1,500.11 -
      - Checkout - - All Gender - - 1,779 - - 1,525.04 - - 3,767.71 -
      - Health and Hygiene - - All Gender - - 16,284 - - 12,972.99 - - 32,571.86 -
      - Household - - All Gender - - 27,038 - - 24,170.73 - - 60,469.89 -
      - Periodicals - - All Gender - - 4,294 - - 3,614.55 - - 9,056.76 -
      - Bulk Mail - - All Products - - All Gender - - 4,320 - - 3,740.95 - - 9,349.07 -
      - Cash Register Handout - - All Products - - All Gender - - 6,697 - - 5,715.67 - - 14,321.33 -
      - Daily Paper - - All Products - - All Gender - - 7,738 - - 6,559.23 - - 16,479.81 -
      - Daily Paper, Radio - - All Products - - All Gender - - 6,891 - - 5,668.77 - - 14,169.42 -
      - Daily Paper, Radio, TV - - All Products - - All Gender - - 9,513 - - 8,055.22 - - 20,173.97 -
      - In-Store Coupon - - All Products - - All Gender - - 3,798 - - 3,263.11 - - 8,162.46 -
      - Drink - - All Gender - - 345 - - 282.44 - - 708.38 -
      - Food - - All Gender - - 2,737 - - 2,345.57 - - 5,889.34 -
      - Baked Goods - - All Gender - - 131 - - 114.11 - - 279.11 -
      - Baking Goods - - All Gender - - 308 - - 252.88 - - 632.01 -
      - Baking Goods - - All Gender - - 146 - - 103.30 - - 261.44 -
      - Jams and Jellies - - All Gender - - 162 - - 149.58 - - 370.57 -
      - Jam - - All Gender - - 55 - - 58.16 - - 141.19 -
      - Jelly - - All Gender - - 32 - - 23.96 - - 62.12 -
      - Peanut Butter - - All Gender - - 22 - - 19.54 - - 48.72 -
      - BBB Best - - All Gender - - 7 - - 6.72 - - 16.10 -
      - CDR - - All Gender - - 10 - - 9.81 - - 24.32 -
      - Landslide - - All Gender - -   - -   - -   -
      - Plato - - All Gender - - 3 - - 2.32 - - 6.32 -
      - Super - - All Gender - - 2 - - .69 - - 1.98 -
      - Preserves - - All Gender - - 53 - - 47.92 - - 118.54 -
      - Breakfast Foods - - All Gender - - 59 - - 49.22 - - 125.19 -
      - F - - 33 - - 22.88 - - 54.84 -
      - M - - 26 - - 26.34 - - 70.35 -
      - Canned Foods - - All Gender - - 245 - - 200.61 - - 506.67 -
      - Canned Products - - All Gender - - 15 - - 9.58 - - 26.17 -
      - Dairy - - All Gender - - 166 - - 153.42 - - 372.01 -
      - Deli - - All Gender - - 180 - - 163.58 - - 392.68 -
      - Eggs - - All Gender - - 56 - - 42.51 - - 108.90 -
      - Frozen Foods - - All Gender - - 374 - - 301.63 - - 773.52 -
      - Meat - - All Gender - - 31 - - 23.91 - - 70.35 -
      - Produce - - All Gender - - 563 - - 499.63 - - 1,257.05 -
      - Seafood - - All Gender - - 34 - - 30.06 - - 76.09 -
      - Snack Foods - - All Gender - - 439 - - 390.35 - - 989.13 -
      - Snacks - - All Gender - - 78 - - 63.77 - - 153.02 -
      - Starchy Foods - - All Gender - - 58 - - 50.30 - - 127.44 -
      - Non-Consumable - - All Gender - - 716 - - 635.10 - - 1,564.74 -
      - Carousel - - All Gender - - 17 - - 8.77 - - 24.18 -
      - Checkout - - All Gender - - 23 - - 15.20 - - 40.19 -
      - Health and Hygiene - - All Gender - - 251 - - 193.53 - - 477.21 -
      - Household - - All Gender - - 374 - - 375.66 - - 916.97 -
      - Periodicals - - All Gender - - 51 - - 41.94 - - 106.19 -
      - No Media - - All Products - - All Gender - - 195,448 - - 165,214.85 - - 414,026.92 -
      - Drink - - All Gender - - 17,896 - - 14,211.41 - - 35,681.85 -
      - Food - - All Gender - - 140,577 - - 119,469.36 - - 299,356.11 -
      - Baked Goods - - All Gender - - 5,753 - - 4,775.86 - - 11,972.46 -
      - Baking Goods - - All Gender - - 14,849 - - 11,226.15 - - 28,312.78 -
      - Baking Goods - - All Gender - - 5,979 - - 4,347.34 - - 11,002.73 -
      - Jams and Jellies - - All Gender - - 8,870 - - 6,878.81 - - 17,310.05 -
      - Jam - - All Gender - - 1,883 - - 1,554.13 - - 3,965.74 -
      - Jelly - - All Gender - - 1,936 - - 1,394.32 - - 3,504.71 -
      - Peanut Butter - - All Gender - - 1,984 - - 1,534.19 - - 3,828.01 -
      - BBB Best - - All Gender - - 406 - - 293.97 - - 735.29 -
      - CDR - - All Gender - - 411 - - 401.88 - - 998.12 -
      - Landslide - - All Gender - - 401 - - 195.51 - - 478.44 -
      - Plato - - All Gender - - 384 - - 331.26 - - 832.92 -
      - Super - - All Gender - - 382 - - 311.57 - - 783.24 -
      - Preserves - - All Gender - - 3,067 - - 2,396.16 - - 6,011.59 -
      - Breakfast Foods - - All Gender - - 2,418 - - 1,996.45 - - 5,016.10 -
      - Canned Foods - - All Gender - - 13,861 - - 11,647.47 - - 29,102.79 -
      - Canned Products - - All Gender - - 1,344 - - 960.82 - - 2,424.98 -
      - Dairy - - All Gender - - 9,510 - - 8,981.13 - - 22,454.02 -
      - Deli - - All Gender - - 8,695 - - 7,353.56 - - 18,410.26 -
      - Eggs - - All Gender - - 2,976 - - 2,640.47 - - 6,606.25 -
      - Frozen Foods - - All Gender - - 19,450 - - 16,127.24 - - 40,411.08 -
      - Meat - - All Gender - - 1,236 - - 1,068.07 - - 2,646.00 -
      - Produce - - All Gender - - 27,637 - - 24,036.36 - - 60,203.58 -
      - Seafood - - All Gender - - 1,292 - - 1,114.69 - - 2,774.43 -
      - Snack Foods - - All Gender - - 22,525 - - 19,800.82 - - 49,680.71 -
      - Snacks - - All Gender - - 5,100 - - 4,264.55 - - 10,690.26 -
      - Starchy Foods - - All Gender - - 3,931 - - 3,475.74 - - 8,650.41 -
      - Non-Consumable - - All Gender - - 36,975 - - 31,534.08 - - 78,988.96 -
      - Carousel - - All Gender - - 584 - - 419.65 - - 1,050.75 -
      - Checkout - - All Gender - - 1,305 - - 1,113.97 - - 2,768.66 -
      - Health and Hygiene - - All Gender - - 11,845 - - 9,413.25 - - 23,621.12 -
      - Household - - All Gender - - 20,091 - - 17,929.20 - - 44,881.13 -
      - Periodicals - - All Gender - - 3,150 - - 2,658.00 - - 6,667.30 -
      - Product Attachment - - All Products - - All Gender - - 7,544 - - 6,306.24 - - 15,898.25 -
      - Drink - - All Gender - - 713 - - 555.05 - - 1,403.65 -
      - Food - - All Gender - - 5,441 - - 4,571.71 - - 11,525.25 -
      - Baked Goods - - All Gender - - 213 - - 175.69 - - 445.60 -
      - Baking Goods - - All Gender - - 547 - - 410.31 - - 1,032.59 -
      - Baking Goods - - All Gender - - 258 - - 191.48 - - 470.58 -
      - Jams and Jellies - - All Gender - - 289 - - 218.83 - - 562.01 -
      - Jam - - All Gender - - 66 - - 48.03 - - 128.68 -
      - Jelly - - All Gender - - 45 - - 34.12 - - 90.62 -
      - Peanut Butter - - All Gender - - 63 - - 47.71 - - 122.31 -
      - BBB Best - - All Gender - - 15 - - 14.53 - - 38.46 -
      - CDR - - All Gender - - 13 - - 11.94 - - 30.57 -
      - Landslide - - All Gender - - 12 - - 5.32 - - 14.28 -
      - Plato - - All Gender - - 9 - - 7.16 - - 17.43 -
      - Super - - All Gender - - 14 - - 8.75 - - 21.57 -
      - Preserves - - All Gender - - 115 - - 88.98 - - 220.40 -
      - Breakfast Foods - - All Gender - - 103 - - 87.35 - - 220.75 -
      - Canned Foods - - All Gender - - 564 - - 463.28 - - 1,154.91 -
      - Canned Products - - All Gender - - 60 - - 51.61 - - 124.24 -
      - Dairy - - All Gender - - 355 - - 339.81 - - 849.78 -
      - Deli - - All Gender - - 324 - - 243.64 - - 618.23 -
      - Eggs - - All Gender - - 118 - - 97.43 - - 241.21 -
      - Frozen Foods - - All Gender - - 812 - - 665.48 - - 1,692.11 -
      - Meat - - All Gender - - 54 - - 51.36 - - 127.83 -
      - Produce - - All Gender - - 1,069 - - 909.24 - - 2,287.61 -
      - Seafood - - All Gender - - 45 - - 36.98 - - 100.61 -
      - Snack Foods - - All Gender - - 819 - - 726.73 - - 1,847.28 -
      - Snacks - - All Gender - - 209 - - 186.22 - - 450.03 -
      - Starchy Foods - - All Gender - - 149 - - 126.59 - - 332.47 -
      - Non-Consumable - - All Gender - - 1,390 - - 1,179.48 - - 2,969.35 -
      - Carousel - - All Gender - - 14 - - 7.99 - - 21.21 -
      - Checkout - - All Gender - - 48 - - 40.45 - - 100.61 -
      - Health and Hygiene - - All Gender - - 440 - - 356.54 - - 901.73 -
      - Household - - All Gender - - 777 - - 690.03 - - 1,737.96 -
      - Periodicals - - All Gender - - 111 - - 84.48 - - 207.84 -
      - Radio - - All Products - - All Gender - - 2,454 - - 2,087.51 - - 5,213.61 -
      - Drink - - All Gender - - 226 - - 182.85 - - 443.68 -
      - Food - - All Gender - - 1,733 - - 1,485.25 - - 3,727.36 -
      - Baked Goods - - All Gender - - 83 - - 76.51 - - 186.20 -
      - Baking Goods - - All Gender - - 157 - - 109.10 - - 274.90 -
      - Baking Goods - - All Gender - - 63 - - 45.02 - - 110.43 -
      - Jams and Jellies - - All Gender - - 94 - - 64.08 - - 164.47 -
      - Jam - - All Gender - - 15 - - 10.42 - - 26.94 -
      - Jelly - - All Gender - - 24 - - 14.54 - - 37.49 -
      - Peanut Butter - - All Gender - - 19 - - 16.85 - - 41.82 -
      - BBB Best - - All Gender - - 10 - - 10.58 - - 24.44 -
      - CDR - - All Gender - -   - -   - -   -
      - Landslide - - All Gender - -   - -   - -   -
      - Plato - - All Gender - - 4 - - 3.77 - - 9.80 -
      - Super - - All Gender - - 5 - - 2.50 - - 7.58 -
      - Preserves - - All Gender - - 36 - - 22.28 - - 58.22 -
      - Breakfast Foods - - All Gender - - 25 - - 18.78 - - 50.22 -
      - Canned Foods - - All Gender - - 158 - - 124.79 - - 307.55 -
      - Canned Products - - All Gender - - 22 - - 17.29 - - 43.42 -
      - Dairy - - All Gender - - 112 - - 92.12 - - 216.79 -
      - Deli - - All Gender - - 129 - - 119.14 - - 307.25 -
      - Eggs - - All Gender - - 25 - - 29.97 - - 71.15 -
      - Frozen Foods - - All Gender - - 253 - - 202.71 - - 507.45 -
      - Meat - - All Gender - - 12 - - 11.53 - - 32.85 -
      - Produce - - All Gender - - 336 - - 292.05 - - 738.20 -
      - Seafood - - All Gender - - 15 - - 13.28 - - 35.58 -
      - Snack Foods - - All Gender - - 290 - - 270.59 - - 674.73 -
      - Snacks - - All Gender - - 60 - - 55.67 - - 144.58 -
      - Starchy Foods - - All Gender - - 56 - - 51.72 - - 136.49 -
      - Non-Consumable - - All Gender - - 495 - - 419.41 - - 1,042.57 -
      - Carousel - - All Gender - - 15 - - 11.15 - - 26.85 -
      - Checkout - - All Gender - - 21 - - 17.00 - - 42.74 -
      - Health and Hygiene - - All Gender - - 145 - - 114.84 - - 289.80 -
      - Household - - All Gender - - 258 - - 233.31 - - 575.07 -
      - Periodicals - - All Gender - - 56 - - 43.12 - - 108.11 -
      - Street Handout - - All Products - - All Gender - - 5,753 - - 4,856.54 - - 12,192.90 -
      - Drink - - All Gender - - 512 - - 372.68 - - 943.42 -
      - Food - - All Gender - - 4,239 - - 3,650.32 - - 9,151.65 -
      - Baked Goods - - All Gender - - 160 - - 120.12 - - 301.62 -
      - Baking Goods - - All Gender - - 498 - - 373.67 - - 923.22 -
      - Baking Goods - - All Gender - - 200 - - 144.16 - - 357.82 -
      - Jams and Jellies - - All Gender - - 298 - - 229.51 - - 565.40 -
      - Jam - - All Gender - - 53 - - 44.30 - - 112.95 -
      - Jelly - - All Gender - - 92 - - 63.14 - - 155.59 -
      - Peanut Butter - - All Gender - - 51 - - 51.06 - - 118.90 -
      - BBB Best - - All Gender - - 11 - - 10.85 - - 25.72 -
      - CDR - - All Gender - - 8 - - 9.06 - - 19.73 -
      - Landslide - - All Gender - - 11 - - 6.90 - - 15.54 -
      - Plato - - All Gender - - 9 - - 8.47 - - 20.89 -
      - Super - - All Gender - - 12 - - 15.78 - - 37.02 -
      - Preserves - - All Gender - - 102 - - 71.02 - - 177.96 -
      - Breakfast Foods - - All Gender - - 81 - - 74.32 - - 192.90 -
      - Canned Foods - - All Gender - - 459 - - 413.21 - - 1,021.86 -
      - Canned Products - - All Gender - - 30 - - 19.43 - - 45.68 -
      - Dairy - - All Gender - - 301 - - 285.98 - - 718.61 -
      - Deli - - All Gender - - 305 - - 253.54 - - 638.30 -
      - Eggs - - All Gender - - 66 - - 59.15 - - 156.82 -
      - Frozen Foods - - All Gender - - 612 - - 520.12 - - 1,313.71 -
      - Meat - - All Gender - - 37 - - 29.82 - - 78.24 -
      - Produce - - All Gender - - 745 - - 662.39 - - 1,639.94 -
      - Seafood - - All Gender - - 37 - - 30.12 - - 72.77 -
      - Snack Foods - - All Gender - - 675 - - 600.23 - - 1,515.68 -
      - Snacks - - All Gender - - 144 - - 128.79 - - 321.16 -
      - Starchy Foods - - All Gender - - 89 - - 79.43 - - 211.14 -
      - Non-Consumable - - All Gender - - 1,002 - - 833.53 - - 2,097.83 -
      - Carousel - - All Gender - - 17 - - 13.53 - - 30.98 -
      - Checkout - - All Gender - - 45 - - 34.77 - - 85.38 -
      - Health and Hygiene - - All Gender - - 402 - - 318.03 - - 802.92 -
      - Household - - All Gender - - 501 - - 436.41 - - 1,105.38 -
      - Periodicals - - All Gender - - 37 - - 30.80 - - 73.17 -
      - Sunday Paper - - All Products - - All Gender - - 4,339 - - 3,673.86 - - 9,092.89 -
      - Drink - - All Gender - - 430 - - 345.53 - - 856.73 -
      - Food - - All Gender - - 3,106 - - 2,646.47 - - 6,559.46 -
      - Baked Goods - - All Gender - - 140 - - 110.79 - - 282.55 -
      - Baking Goods - - All Gender - - 338 - - 239.76 - - 603.86 -
      - Baking Goods - - All Gender - - 170 - - 118.05 - - 298.79 -
      - Jams and Jellies - - All Gender - - 168 - - 121.71 - - 305.07 -
      - Jam - - All Gender - - 24 - - 22.35 - - 54.83 -
      - Jelly - - All Gender - - 27 - - 18.20 - - 47.12 -
      - Peanut Butter - - All Gender - - 51 - - 37.67 - - 96.67 -
      - BBB Best - - All Gender - - 10 - - 6.08 - - 16.22 -
      - CDR - - All Gender - - 10 - - 10.47 - - 26.50 -
      - Landslide - - All Gender - - 15 - - 6.20 - - 16.31 -
      - Plato - - All Gender - - 16 - - 14.93 - - 37.64 -
      - Super - - All Gender - -   - -   - -   -
      - Preserves - - All Gender - - 66 - - 43.49 - - 106.45 -
      - Breakfast Foods - - All Gender - - 55 - - 49.80 - - 120.23 -
      - Canned Foods - - All Gender - - 283 - - 249.46 - - 605.11 -
      - Canned Products - - All Gender - - 34 - - 29.65 - - 72.18 -
      - Dairy - - All Gender - - 200 - - 201.94 - - 497.91 -
      - Deli - - All Gender - - 228 - - 188.37 - - 467.53 -
      - Eggs - - All Gender - - 54 - - 47.68 - - 118.44 -
      - Frozen Foods - - All Gender - - 425 - - 330.81 - - 839.15 -
      - Meat - - All Gender - - 18 - - 19.85 - - 52.20 -
      - Produce - - All Gender - - 603 - - 520.95 - - 1,274.70 -
      - Seafood - - All Gender - - 27 - - 26.82 - - 69.49 -
      - Snack Foods - - All Gender - - 469 - - 413.18 - - 1,027.98 -
      - Snacks - - All Gender - - 123 - - 108.50 - - 261.38 -
      - Starchy Foods - - All Gender - - 109 - - 108.91 - - 266.75 -
      - Non-Consumable - - All Gender - - 803 - - 681.86 - - 1,676.70 -
      - Carousel - - All Gender - - 7 - - 6.70 - - 14.68 -
      - Checkout - - All Gender - - 17 - - 13.09 - - 30.89 -
      - Health and Hygiene - - All Gender - - 278 - - 227.06 - - 565.99 -
      - Household - - All Gender - - 420 - - 371.58 - - 911.69 -
      - Periodicals - - All Gender - - 81 - - 63.43 - - 153.45 -
      - Sunday Paper, Radio - - All Products - - All Gender - - 5,945 - - 5,027.31 - - 12,551.96 -
      - Drink - - All Gender - - 591 - - 454.03 - - 1,129.94 -
      - Food - - All Gender - - 4,239 - - 3,612.38 - - 9,033.23 -
      - Baked Goods - - All Gender - - 152 - - 109.11 - - 274.39 -
      - Baking Goods - - All Gender - - 482 - - 367.13 - - 913.84 -
      - Baking Goods - - All Gender - - 206 - - 152.72 - - 381.59 -
      - Jams and Jellies - - All Gender - - 276 - - 214.41 - - 532.25 -
      - Jam - - All Gender - - 52 - - 52.39 - - 126.62 -
      - Jelly - - All Gender - - 74 - - 53.93 - - 135.03 -
      - Peanut Butter - - All Gender - - 64 - - 50.10 - - 126.71 -
      - BBB Best - - All Gender - - 14 - - 11.58 - - 27.40 -
      - CDR - - All Gender - - 17 - - 14.68 - - 41.25 -
      - Landslide - - All Gender - - 14 - - 6.62 - - 17.04 -
      - Plato - - All Gender - - 7 - - 6.91 - - 17.15 -
      - Super - - All Gender - - 12 - - 10.31 - - 23.87 -
      - Preserves - - All Gender - - 86 - - 57.99 - - 143.89 -
      - Breakfast Foods - - All Gender - - 80 - - 62.80 - - 154.04 -
      - Canned Foods - - All Gender - - 456 - - 361.79 - - 914.81 -
      - Canned Products - - All Gender - - 45 - - 39.72 - - 95.88 -
      - Dairy - - All Gender - - 283 - - 296.91 - - 722.75 -
      - Deli - - All Gender - - 252 - - 190.32 - - 479.59 -
      - Eggs - - All Gender - - 114 - - 104.65 - - 256.15 -
      - Frozen Foods - - All Gender - - 599 - - 490.33 - - 1,222.54 -
      - Meat - - All Gender - - 40 - - 31.66 - - 84.76 -
      - Produce - - All Gender - - 858 - - 752.62 - - 1,886.01 -
      - Seafood - - All Gender - - 27 - - 20.66 - - 50.39 -
      - Snack Foods - - All Gender - - 596 - - 555.70 - - 1,402.21 -
      - Snacks - - All Gender - - 147 - - 120.43 - - 304.18 -
      - Starchy Foods - - All Gender - - 108 - - 108.55 - - 271.69 -
      - Non-Consumable - - All Gender - - 1,115 - - 960.90 - - 2,388.79 -
      - Carousel - - All Gender - - 18 - - 10.99 - - 26.94 -
      - Checkout - - All Gender - - 26 - - 24.68 - - 62.14 -
      - Health and Hygiene - - All Gender - - 378 - - 309.37 - - 771.48 -
      - Household - - All Gender - - 585 - - 516.99 - - 1,276.16 -
      - Periodicals - - All Gender - - 108 - - 98.86 - - 252.07 -
      - Sunday Paper, Radio, TV - - All Products - - All Gender - - 2,726 - - 2,341.58 - - 5,819.33 -
      - Drink - - All Gender - - 225 - - 163.09 - - 403.51 -
      - Food - - All Gender - - 2,021 - - 1,762.18 - - 4,377.85 -
      - Baked Goods - - All Gender - - 67 - - 66.17 - - 163.29 -
      - Baking Goods - - All Gender - - 228 - - 182.98 - - 455.90 -
      - Baking Goods - - All Gender - - 90 - - 73.09 - - 176.63 -
      - Jams and Jellies - - All Gender - - 138 - - 109.90 - - 279.27 -
      - Jam - - All Gender - - 37 - - 31.30 - - 78.56 -
      - Jelly - - All Gender - - 27 - - 16.18 - - 39.92 -
      - Peanut Butter - - All Gender - - 30 - - 24.01 - - 64.19 -
      - BBB Best - - All Gender - - 11 - - 9.78 - - 23.86 -
      - CDR - - All Gender - -   - -   - -   -
      - Landslide - - All Gender - - 4 - - 2.39 - - 5.68 -
      - Plato - - All Gender - - 5 - - 3.85 - - 11.60 -
      - Super - - All Gender - - 10 - - 7.99 - - 23.05 -
      - Preserves - - All Gender - - 44 - - 38.41 - - 96.60 -
      - Breakfast Foods - - All Gender - - 38 - - 32.76 - - 89.85 -
      - Canned Foods - - All Gender - - 180 - - 138.77 - - 340.04 -
      - Canned Products - - All Gender - - 14 - - 12.00 - - 28.28 -
      - Dairy - - All Gender - - 121 - - 125.32 - - 305.43 -
      - Deli - - All Gender - - 131 - - 98.93 - - 245.42 -
      - Eggs - - All Gender - - 39 - - 39.57 - - 91.99 -
      - Frozen Foods - - All Gender - - 279 - - 207.59 - - 514.95 -
      - Meat - - All Gender - - 12 - - 11.77 - - 30.23 -
      - Produce - - All Gender - - 411 - - 382.14 - - 943.93 -
      - Seafood - - All Gender - - 31 - - 28.07 - - 69.82 -
      - Snack Foods - - All Gender - - 346 - - 318.26 - - 798.50 -
      - Snacks - - All Gender - - 75 - - 65.49 - - 174.02 -
      - Starchy Foods - - All Gender - - 49 - - 52.37 - - 126.20 -
      - Non-Consumable - - All Gender - - 480 - - 416.30 - - 1,037.97 -
      - Carousel - - All Gender - - 21 - - 11.63 - - 27.92 -
      - Checkout - - All Gender - - 10 - - 8.12 - - 19.80 -
      - Health and Hygiene - - All Gender - - 138 - - 110.35 - - 276.31 -
      - Household - - All Gender - - 262 - - 244.90 - - 608.52 -
      - Periodicals - - All Gender - - 49 - - 41.30 - - 105.42 -
      - TV - - All Products - - All Gender - - 3,607 - - 3,116.40 - - 7,786.21 -
      - Drink - - All Gender - - 332 - - 283.18 - - 721.07 -
      - Food - - All Gender - - 2,563 - - 2,238.13 - - 5,573.27 -
      - Baked Goods - - All Gender - - 114 - - 103.40 - - 262.97 -
      - Baking Goods - - All Gender - - 237 - - 185.55 - - 464.23 -
      - Baking Goods - - All Gender - - 95 - - 74.29 - - 190.59 -
      - Jams and Jellies - - All Gender - - 142 - - 111.25 - - 273.64 -
      - Jam - - All Gender - - 38 - - 32.28 - - 77.58 -
      - Jelly - - All Gender - - 35 - - 24.64 - - 63.38 -
      - Peanut Butter - - All Gender - - 31 - - 21.83 - - 56.80 -
      - BBB Best - - All Gender - -   - -   - -   -
      - CDR - - All Gender - - 11 - - 9.78 - - 27.19 -
      - Landslide - - All Gender - - 7 - - 2.61 - - 7.12 -
      - Plato - - All Gender - - 6 - - 4.95 - - 12.13 -
      - Super - - All Gender - - 7 - - 4.48 - - 10.36 -
      - Preserves - - All Gender - - 38 - - 32.51 - - 75.88 -
      - Breakfast Foods - - All Gender - - 36 - - 30.11 - - 79.89 -
      - Canned Foods - - All Gender - - 240 - - 200.00 - - 519.91 -
      - Canned Products - - All Gender - - 26 - - 15.00 - - 38.65 -
      - Dairy - - All Gender - - 179 - - 183.73 - - 458.87 -
      - Deli - - All Gender - - 155 - - 139.76 - - 342.51 -
      - Eggs - - All Gender - - 42 - - 32.74 - - 80.93 -
      - Frozen Foods - - All Gender - - 352 - - 300.42 - - 738.40 -
      - Meat - - All Gender - - 22 - - 19.76 - - 49.27 -
      - Produce - - All Gender - - 543 - - 456.53 - - 1,145.45 -
      - Seafood - - All Gender - - 34 - - 30.71 - - 75.47 -
      - Snack Foods - - All Gender - - 401 - - 377.01 - - 927.50 -
      - Snacks - - All Gender - - 99 - - 92.80 - - 220.54 -
      - Starchy Foods - - All Gender - - 83 - - 70.61 - - 168.68 -
      - Non-Consumable - - All Gender - - 712 - - 595.08 - - 1,491.87 -
      - Carousel - - All Gender - - 4 - - 3.13 - - 9.20 -
      - Checkout - - All Gender - - 34 - - 34.12 - - 86.21 -
      - Health and Hygiene - - All Gender - - 249 - - 196.08 - - 486.46 -
      - Household - - All Gender - - 361 - - 316.09 - - 795.40 -
      - Periodicals - - All Gender - - 64 - - 45.67 - - 114.60 -
      +   + + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + All Products + + All Gender + + 266,773 + + 225,627.23 + + 565,238.13 +
      + Drink + + All Gender + + 24,597 + + 19,477.23 + + 48,836.21 +
      + Food + + All Gender + + 191,940 + + 163,270.72 + + 409,035.59 +
      + Baked Goods + + All Gender + + 7,870 + + 6,564.09 + + 16,455.43 +
      + Baking Goods + + All Gender + + 20,245 + + 15,370.61 + + 38,670.41 +
      + Baking Goods + + All Gender + + 8,357 + + 6,123.32 + + 15,446.69 +
      + F + + 4,005 + + 2,907.70 + + 7,313.61 +
      + M + + 4,352 + + 3,215.62 + + 8,133.08 +
      + Jams and Jellies + + All Gender + + 11,888 + + 9,247.29 + + 23,223.72 +
      + Jam + + All Gender + + 2,556 + + 2,132.27 + + 5,401.81 +
      + Jelly + + All Gender + + 2,565 + + 1,830.04 + + 4,609.61 +
      + F + + 1,309 + + 956.94 + + 2,414.94 +
      + M + + 1,256 + + 873.10 + + 2,194.67 +
      + Peanut Butter + + All Gender + + 2,667 + + 2,097.37 + + 5,231.08 +
      + BBB Best + + All Gender + + 556 + + 424.38 + + 1,055.72 +
      + F + + 271 + + 201.08 + + 500.39 +
      + M + + 285 + + 223.30 + + 555.33 +
      + BBB Best Chunky Peanut Butter + + All Gender + + 188 + + 147.32 + + 370.36 +
      + F + + 107 + + 85.81 + + 210.79 +
      + M + + 81 + + 61.50 + + 159.57 +
      + BBB Best Creamy Peanut Butter + + All Gender + + 201 + + 87.86 + + 221.10 +
      + F + + 99 + + 43.35 + + 108.90 +
      + M + + 102 + + 44.51 + + 112.20 +
      + BBB Best Extra Chunky Peanut Butter + + All Gender + + 167 + + 189.21 + + 464.26 +
      + F + + 65 + + 71.92 + + 180.70 +
      + M + + 102 + + 117.29 + + 283.56 +
      + CDR + + All Gender + + 545 + + 538.88 + + 1,326.30 +
      + Landslide + + All Gender + + 531 + + 256.16 + + 635.29 +
      + Plato + + All Gender + + 520 + + 447.73 + + 1,132.16 +
      + Super + + All Gender + + 515 + + 430.21 + + 1,081.61 +
      + Preserves + + All Gender + + 4,100 + + 3,187.61 + + 7,981.22 +
      + F + + 1,946 + + 1,472.42 + + 3,717.80 +
      + M + + 2,154 + + 1,715.19 + + 4,263.42 +
      + Breakfast Foods + + All Gender + + 3,317 + + 2,756.80 + + 6,941.46 +
      + Canned Foods + + All Gender + + 19,026 + + 15,894.53 + + 39,774.34 +
      + Canned Anchovies + + All Gender + + 900 + + 913.88 + + 2,296.38 +
      + Canned Clams + + All Gender + + 882 + + 759.80 + + 1,912.68 +
      + Clams + + All Gender + + 882 + + 759.80 + + 1,912.68 +
      + Better + + All Gender + + 189 + + 151.14 + + 398.79 +
      + Blue Label + + All Gender + + 165 + + 112.82 + + 278.85 +
      + Bravo + + All Gender + + 184 + + 280.70 + + 708.40 +
      + Just Right + + All Gender + + 177 + + 161.96 + + 394.71 +
      + Pleasant + + All Gender + + 167 + + 53.17 + + 131.93 +
      + Canned Oysters + + All Gender + + 708 + + 571.50 + + 1,442.77 +
      + Canned Sardines + + All Gender + + 819 + + 537.59 + + 1,357.80 +
      + Canned Shrimp + + All Gender + + 804 + + 858.39 + + 2,146.49 +
      + Canned Soup + + All Gender + + 8,006 + + 6,408.29 + + 15,966.10 +
      + Canned Tuna + + All Gender + + 1,710 + + 1,288.52 + + 3,210.76 +
      + Vegetables + + All Gender + + 5,197 + + 4,556.57 + + 11,441.36 +
      + Canned Products + + All Gender + + 1,812 + + 1,317.13 + + 3,314.52 +
      + Dairy + + All Gender + + 12,885 + + 12,228.85 + + 30,508.85 +
      + Deli + + All Gender + + 12,037 + + 10,108.87 + + 25,318.93 +
      + Meat + + All Gender + + 9,433 + + 8,215.81 + + 20,616.29 +
      + Bologna + + All Gender + + 2,588 + + 2,340.24 + + 5,859.95 +
      + Deli Meats + + All Gender + + 3,339 + + 2,851.18 + + 7,191.24 +
      + F + + 1,653 + + 1,414.49 + + 3,579.34 +
      + M + + 1,686 + + 1,436.69 + + 3,611.90 +
      + Fresh Chicken + + All Gender + + 878 + + 842.85 + + 2,091.52 +
      + Hot Dogs + + All Gender + + 2,628 + + 2,181.55 + + 5,473.58 +
      + Side Dishes + + All Gender + + 2,604 + + 1,893.06 + + 4,702.64 +
      + Eggs + + All Gender + + 4,132 + + 3,684.90 + + 9,200.76 +
      + Frozen Foods + + All Gender + + 26,655 + + 22,030.66 + + 55,207.50 +
      + Meat + + All Gender + + 1,714 + + 1,465.42 + + 3,669.89 +
      + Produce + + All Gender + + 37,792 + + 32,831.33 + + 82,248.42 +
      + Seafood + + All Gender + + 1,764 + + 1,520.70 + + 3,809.14 +
      + Snack Foods + + All Gender + + 30,545 + + 26,963.34 + + 67,609.82 +
      + Snacks + + All Gender + + 6,884 + + 5,827.58 + + 14,550.05 +
      + Starchy Foods + + All Gender + + 5,262 + + 4,705.91 + + 11,756.07 +
      + Non-Consumable + + All Gender + + 50,236 + + 42,879.28 + + 107,366.33 +
      + Carousel + + All Gender + + 841 + + 595.97 + + 1,500.11 +
      + Checkout + + All Gender + + 1,779 + + 1,525.04 + + 3,767.71 +
      + Health and Hygiene + + All Gender + + 16,284 + + 12,972.99 + + 32,571.86 +
      + Household + + All Gender + + 27,038 + + 24,170.73 + + 60,469.89 +
      + Periodicals + + All Gender + + 4,294 + + 3,614.55 + + 9,056.76 +
      + Bulk Mail + + All Products + + All Gender + + 4,320 + + 3,740.95 + + 9,349.07 +
      + Cash Register Handout + + All Products + + All Gender + + 6,697 + + 5,715.67 + + 14,321.33 +
      + Daily Paper + + All Products + + All Gender + + 7,738 + + 6,559.23 + + 16,479.81 +
      + Daily Paper, Radio + + All Products + + All Gender + + 6,891 + + 5,668.77 + + 14,169.42 +
      + Daily Paper, Radio, TV + + All Products + + All Gender + + 9,513 + + 8,055.22 + + 20,173.97 +
      + In-Store Coupon + + All Products + + All Gender + + 3,798 + + 3,263.11 + + 8,162.46 +
      + Drink + + All Gender + + 345 + + 282.44 + + 708.38 +
      + Food + + All Gender + + 2,737 + + 2,345.57 + + 5,889.34 +
      + Baked Goods + + All Gender + + 131 + + 114.11 + + 279.11 +
      + Baking Goods + + All Gender + + 308 + + 252.88 + + 632.01 +
      + Baking Goods + + All Gender + + 146 + + 103.30 + + 261.44 +
      + Jams and Jellies + + All Gender + + 162 + + 149.58 + + 370.57 +
      + Jam + + All Gender + + 55 + + 58.16 + + 141.19 +
      + Jelly + + All Gender + + 32 + + 23.96 + + 62.12 +
      + Peanut Butter + + All Gender + + 22 + + 19.54 + + 48.72 +
      + BBB Best + + All Gender + + 7 + + 6.72 + + 16.10 +
      + CDR + + All Gender + + 10 + + 9.81 + + 24.32 +
      + Landslide + + All Gender + +   + +   + +   +
      + Plato + + All Gender + + 3 + + 2.32 + + 6.32 +
      + Super + + All Gender + + 2 + + .69 + + 1.98 +
      + Preserves + + All Gender + + 53 + + 47.92 + + 118.54 +
      + Breakfast Foods + + All Gender + + 59 + + 49.22 + + 125.19 +
      + F + + 33 + + 22.88 + + 54.84 +
      + M + + 26 + + 26.34 + + 70.35 +
      + Canned Foods + + All Gender + + 245 + + 200.61 + + 506.67 +
      + Canned Products + + All Gender + + 15 + + 9.58 + + 26.17 +
      + Dairy + + All Gender + + 166 + + 153.42 + + 372.01 +
      + Deli + + All Gender + + 180 + + 163.58 + + 392.68 +
      + Eggs + + All Gender + + 56 + + 42.51 + + 108.90 +
      + Frozen Foods + + All Gender + + 374 + + 301.63 + + 773.52 +
      + Meat + + All Gender + + 31 + + 23.91 + + 70.35 +
      + Produce + + All Gender + + 563 + + 499.63 + + 1,257.05 +
      + Seafood + + All Gender + + 34 + + 30.06 + + 76.09 +
      + Snack Foods + + All Gender + + 439 + + 390.35 + + 989.13 +
      + Snacks + + All Gender + + 78 + + 63.77 + + 153.02 +
      + Starchy Foods + + All Gender + + 58 + + 50.30 + + 127.44 +
      + Non-Consumable + + All Gender + + 716 + + 635.10 + + 1,564.74 +
      + Carousel + + All Gender + + 17 + + 8.77 + + 24.18 +
      + Checkout + + All Gender + + 23 + + 15.20 + + 40.19 +
      + Health and Hygiene + + All Gender + + 251 + + 193.53 + + 477.21 +
      + Household + + All Gender + + 374 + + 375.66 + + 916.97 +
      + Periodicals + + All Gender + + 51 + + 41.94 + + 106.19 +
      + No Media + + All Products + + All Gender + + 195,448 + + 165,214.85 + + 414,026.92 +
      + Drink + + All Gender + + 17,896 + + 14,211.41 + + 35,681.85 +
      + Food + + All Gender + + 140,577 + + 119,469.36 + + 299,356.11 +
      + Baked Goods + + All Gender + + 5,753 + + 4,775.86 + + 11,972.46 +
      + Baking Goods + + All Gender + + 14,849 + + 11,226.15 + + 28,312.78 +
      + Baking Goods + + All Gender + + 5,979 + + 4,347.34 + + 11,002.73 +
      + Jams and Jellies + + All Gender + + 8,870 + + 6,878.81 + + 17,310.05 +
      + Jam + + All Gender + + 1,883 + + 1,554.13 + + 3,965.74 +
      + Jelly + + All Gender + + 1,936 + + 1,394.32 + + 3,504.71 +
      + Peanut Butter + + All Gender + + 1,984 + + 1,534.19 + + 3,828.01 +
      + BBB Best + + All Gender + + 406 + + 293.97 + + 735.29 +
      + CDR + + All Gender + + 411 + + 401.88 + + 998.12 +
      + Landslide + + All Gender + + 401 + + 195.51 + + 478.44 +
      + Plato + + All Gender + + 384 + + 331.26 + + 832.92 +
      + Super + + All Gender + + 382 + + 311.57 + + 783.24 +
      + Preserves + + All Gender + + 3,067 + + 2,396.16 + + 6,011.59 +
      + Breakfast Foods + + All Gender + + 2,418 + + 1,996.45 + + 5,016.10 +
      + Canned Foods + + All Gender + + 13,861 + + 11,647.47 + + 29,102.79 +
      + Canned Products + + All Gender + + 1,344 + + 960.82 + + 2,424.98 +
      + Dairy + + All Gender + + 9,510 + + 8,981.13 + + 22,454.02 +
      + Deli + + All Gender + + 8,695 + + 7,353.56 + + 18,410.26 +
      + Eggs + + All Gender + + 2,976 + + 2,640.47 + + 6,606.25 +
      + Frozen Foods + + All Gender + + 19,450 + + 16,127.24 + + 40,411.08 +
      + Meat + + All Gender + + 1,236 + + 1,068.07 + + 2,646.00 +
      + Produce + + All Gender + + 27,637 + + 24,036.36 + + 60,203.58 +
      + Seafood + + All Gender + + 1,292 + + 1,114.69 + + 2,774.43 +
      + Snack Foods + + All Gender + + 22,525 + + 19,800.82 + + 49,680.71 +
      + Snacks + + All Gender + + 5,100 + + 4,264.55 + + 10,690.26 +
      + Starchy Foods + + All Gender + + 3,931 + + 3,475.74 + + 8,650.41 +
      + Non-Consumable + + All Gender + + 36,975 + + 31,534.08 + + 78,988.96 +
      + Carousel + + All Gender + + 584 + + 419.65 + + 1,050.75 +
      + Checkout + + All Gender + + 1,305 + + 1,113.97 + + 2,768.66 +
      + Health and Hygiene + + All Gender + + 11,845 + + 9,413.25 + + 23,621.12 +
      + Household + + All Gender + + 20,091 + + 17,929.20 + + 44,881.13 +
      + Periodicals + + All Gender + + 3,150 + + 2,658.00 + + 6,667.30 +
      + Product Attachment + + All Products + + All Gender + + 7,544 + + 6,306.24 + + 15,898.25 +
      + Drink + + All Gender + + 713 + + 555.05 + + 1,403.65 +
      + Food + + All Gender + + 5,441 + + 4,571.71 + + 11,525.25 +
      + Baked Goods + + All Gender + + 213 + + 175.69 + + 445.60 +
      + Baking Goods + + All Gender + + 547 + + 410.31 + + 1,032.59 +
      + Baking Goods + + All Gender + + 258 + + 191.48 + + 470.58 +
      + Jams and Jellies + + All Gender + + 289 + + 218.83 + + 562.01 +
      + Jam + + All Gender + + 66 + + 48.03 + + 128.68 +
      + Jelly + + All Gender + + 45 + + 34.12 + + 90.62 +
      + Peanut Butter + + All Gender + + 63 + + 47.71 + + 122.31 +
      + BBB Best + + All Gender + + 15 + + 14.53 + + 38.46 +
      + CDR + + All Gender + + 13 + + 11.94 + + 30.57 +
      + Landslide + + All Gender + + 12 + + 5.32 + + 14.28 +
      + Plato + + All Gender + + 9 + + 7.16 + + 17.43 +
      + Super + + All Gender + + 14 + + 8.75 + + 21.57 +
      + Preserves + + All Gender + + 115 + + 88.98 + + 220.40 +
      + Breakfast Foods + + All Gender + + 103 + + 87.35 + + 220.75 +
      + Canned Foods + + All Gender + + 564 + + 463.28 + + 1,154.91 +
      + Canned Products + + All Gender + + 60 + + 51.61 + + 124.24 +
      + Dairy + + All Gender + + 355 + + 339.81 + + 849.78 +
      + Deli + + All Gender + + 324 + + 243.64 + + 618.23 +
      + Eggs + + All Gender + + 118 + + 97.43 + + 241.21 +
      + Frozen Foods + + All Gender + + 812 + + 665.48 + + 1,692.11 +
      + Meat + + All Gender + + 54 + + 51.36 + + 127.83 +
      + Produce + + All Gender + + 1,069 + + 909.24 + + 2,287.61 +
      + Seafood + + All Gender + + 45 + + 36.98 + + 100.61 +
      + Snack Foods + + All Gender + + 819 + + 726.73 + + 1,847.28 +
      + Snacks + + All Gender + + 209 + + 186.22 + + 450.03 +
      + Starchy Foods + + All Gender + + 149 + + 126.59 + + 332.47 +
      + Non-Consumable + + All Gender + + 1,390 + + 1,179.48 + + 2,969.35 +
      + Carousel + + All Gender + + 14 + + 7.99 + + 21.21 +
      + Checkout + + All Gender + + 48 + + 40.45 + + 100.61 +
      + Health and Hygiene + + All Gender + + 440 + + 356.54 + + 901.73 +
      + Household + + All Gender + + 777 + + 690.03 + + 1,737.96 +
      + Periodicals + + All Gender + + 111 + + 84.48 + + 207.84 +
      + Radio + + All Products + + All Gender + + 2,454 + + 2,087.51 + + 5,213.61 +
      + Drink + + All Gender + + 226 + + 182.85 + + 443.68 +
      + Food + + All Gender + + 1,733 + + 1,485.25 + + 3,727.36 +
      + Baked Goods + + All Gender + + 83 + + 76.51 + + 186.20 +
      + Baking Goods + + All Gender + + 157 + + 109.10 + + 274.90 +
      + Baking Goods + + All Gender + + 63 + + 45.02 + + 110.43 +
      + Jams and Jellies + + All Gender + + 94 + + 64.08 + + 164.47 +
      + Jam + + All Gender + + 15 + + 10.42 + + 26.94 +
      + Jelly + + All Gender + + 24 + + 14.54 + + 37.49 +
      + Peanut Butter + + All Gender + + 19 + + 16.85 + + 41.82 +
      + BBB Best + + All Gender + + 10 + + 10.58 + + 24.44 +
      + CDR + + All Gender + +   + +   + +   +
      + Landslide + + All Gender + +   + +   + +   +
      + Plato + + All Gender + + 4 + + 3.77 + + 9.80 +
      + Super + + All Gender + + 5 + + 2.50 + + 7.58 +
      + Preserves + + All Gender + + 36 + + 22.28 + + 58.22 +
      + Breakfast Foods + + All Gender + + 25 + + 18.78 + + 50.22 +
      + Canned Foods + + All Gender + + 158 + + 124.79 + + 307.55 +
      + Canned Products + + All Gender + + 22 + + 17.29 + + 43.42 +
      + Dairy + + All Gender + + 112 + + 92.12 + + 216.79 +
      + Deli + + All Gender + + 129 + + 119.14 + + 307.25 +
      + Eggs + + All Gender + + 25 + + 29.97 + + 71.15 +
      + Frozen Foods + + All Gender + + 253 + + 202.71 + + 507.45 +
      + Meat + + All Gender + + 12 + + 11.53 + + 32.85 +
      + Produce + + All Gender + + 336 + + 292.05 + + 738.20 +
      + Seafood + + All Gender + + 15 + + 13.28 + + 35.58 +
      + Snack Foods + + All Gender + + 290 + + 270.59 + + 674.73 +
      + Snacks + + All Gender + + 60 + + 55.67 + + 144.58 +
      + Starchy Foods + + All Gender + + 56 + + 51.72 + + 136.49 +
      + Non-Consumable + + All Gender + + 495 + + 419.41 + + 1,042.57 +
      + Carousel + + All Gender + + 15 + + 11.15 + + 26.85 +
      + Checkout + + All Gender + + 21 + + 17.00 + + 42.74 +
      + Health and Hygiene + + All Gender + + 145 + + 114.84 + + 289.80 +
      + Household + + All Gender + + 258 + + 233.31 + + 575.07 +
      + Periodicals + + All Gender + + 56 + + 43.12 + + 108.11 +
      + Street Handout + + All Products + + All Gender + + 5,753 + + 4,856.54 + + 12,192.90 +
      + Drink + + All Gender + + 512 + + 372.68 + + 943.42 +
      + Food + + All Gender + + 4,239 + + 3,650.32 + + 9,151.65 +
      + Baked Goods + + All Gender + + 160 + + 120.12 + + 301.62 +
      + Baking Goods + + All Gender + + 498 + + 373.67 + + 923.22 +
      + Baking Goods + + All Gender + + 200 + + 144.16 + + 357.82 +
      + Jams and Jellies + + All Gender + + 298 + + 229.51 + + 565.40 +
      + Jam + + All Gender + + 53 + + 44.30 + + 112.95 +
      + Jelly + + All Gender + + 92 + + 63.14 + + 155.59 +
      + Peanut Butter + + All Gender + + 51 + + 51.06 + + 118.90 +
      + BBB Best + + All Gender + + 11 + + 10.85 + + 25.72 +
      + CDR + + All Gender + + 8 + + 9.06 + + 19.73 +
      + Landslide + + All Gender + + 11 + + 6.90 + + 15.54 +
      + Plato + + All Gender + + 9 + + 8.47 + + 20.89 +
      + Super + + All Gender + + 12 + + 15.78 + + 37.02 +
      + Preserves + + All Gender + + 102 + + 71.02 + + 177.96 +
      + Breakfast Foods + + All Gender + + 81 + + 74.32 + + 192.90 +
      + Canned Foods + + All Gender + + 459 + + 413.21 + + 1,021.86 +
      + Canned Products + + All Gender + + 30 + + 19.43 + + 45.68 +
      + Dairy + + All Gender + + 301 + + 285.98 + + 718.61 +
      + Deli + + All Gender + + 305 + + 253.54 + + 638.30 +
      + Eggs + + All Gender + + 66 + + 59.15 + + 156.82 +
      + Frozen Foods + + All Gender + + 612 + + 520.12 + + 1,313.71 +
      + Meat + + All Gender + + 37 + + 29.82 + + 78.24 +
      + Produce + + All Gender + + 745 + + 662.39 + + 1,639.94 +
      + Seafood + + All Gender + + 37 + + 30.12 + + 72.77 +
      + Snack Foods + + All Gender + + 675 + + 600.23 + + 1,515.68 +
      + Snacks + + All Gender + + 144 + + 128.79 + + 321.16 +
      + Starchy Foods + + All Gender + + 89 + + 79.43 + + 211.14 +
      + Non-Consumable + + All Gender + + 1,002 + + 833.53 + + 2,097.83 +
      + Carousel + + All Gender + + 17 + + 13.53 + + 30.98 +
      + Checkout + + All Gender + + 45 + + 34.77 + + 85.38 +
      + Health and Hygiene + + All Gender + + 402 + + 318.03 + + 802.92 +
      + Household + + All Gender + + 501 + + 436.41 + + 1,105.38 +
      + Periodicals + + All Gender + + 37 + + 30.80 + + 73.17 +
      + Sunday Paper + + All Products + + All Gender + + 4,339 + + 3,673.86 + + 9,092.89 +
      + Drink + + All Gender + + 430 + + 345.53 + + 856.73 +
      + Food + + All Gender + + 3,106 + + 2,646.47 + + 6,559.46 +
      + Baked Goods + + All Gender + + 140 + + 110.79 + + 282.55 +
      + Baking Goods + + All Gender + + 338 + + 239.76 + + 603.86 +
      + Baking Goods + + All Gender + + 170 + + 118.05 + + 298.79 +
      + Jams and Jellies + + All Gender + + 168 + + 121.71 + + 305.07 +
      + Jam + + All Gender + + 24 + + 22.35 + + 54.83 +
      + Jelly + + All Gender + + 27 + + 18.20 + + 47.12 +
      + Peanut Butter + + All Gender + + 51 + + 37.67 + + 96.67 +
      + BBB Best + + All Gender + + 10 + + 6.08 + + 16.22 +
      + CDR + + All Gender + + 10 + + 10.47 + + 26.50 +
      + Landslide + + All Gender + + 15 + + 6.20 + + 16.31 +
      + Plato + + All Gender + + 16 + + 14.93 + + 37.64 +
      + Super + + All Gender + +   + +   + +   +
      + Preserves + + All Gender + + 66 + + 43.49 + + 106.45 +
      + Breakfast Foods + + All Gender + + 55 + + 49.80 + + 120.23 +
      + Canned Foods + + All Gender + + 283 + + 249.46 + + 605.11 +
      + Canned Products + + All Gender + + 34 + + 29.65 + + 72.18 +
      + Dairy + + All Gender + + 200 + + 201.94 + + 497.91 +
      + Deli + + All Gender + + 228 + + 188.37 + + 467.53 +
      + Eggs + + All Gender + + 54 + + 47.68 + + 118.44 +
      + Frozen Foods + + All Gender + + 425 + + 330.81 + + 839.15 +
      + Meat + + All Gender + + 18 + + 19.85 + + 52.20 +
      + Produce + + All Gender + + 603 + + 520.95 + + 1,274.70 +
      + Seafood + + All Gender + + 27 + + 26.82 + + 69.49 +
      + Snack Foods + + All Gender + + 469 + + 413.18 + + 1,027.98 +
      + Snacks + + All Gender + + 123 + + 108.50 + + 261.38 +
      + Starchy Foods + + All Gender + + 109 + + 108.91 + + 266.75 +
      + Non-Consumable + + All Gender + + 803 + + 681.86 + + 1,676.70 +
      + Carousel + + All Gender + + 7 + + 6.70 + + 14.68 +
      + Checkout + + All Gender + + 17 + + 13.09 + + 30.89 +
      + Health and Hygiene + + All Gender + + 278 + + 227.06 + + 565.99 +
      + Household + + All Gender + + 420 + + 371.58 + + 911.69 +
      + Periodicals + + All Gender + + 81 + + 63.43 + + 153.45 +
      + Sunday Paper, Radio + + All Products + + All Gender + + 5,945 + + 5,027.31 + + 12,551.96 +
      + Drink + + All Gender + + 591 + + 454.03 + + 1,129.94 +
      + Food + + All Gender + + 4,239 + + 3,612.38 + + 9,033.23 +
      + Baked Goods + + All Gender + + 152 + + 109.11 + + 274.39 +
      + Baking Goods + + All Gender + + 482 + + 367.13 + + 913.84 +
      + Baking Goods + + All Gender + + 206 + + 152.72 + + 381.59 +
      + Jams and Jellies + + All Gender + + 276 + + 214.41 + + 532.25 +
      + Jam + + All Gender + + 52 + + 52.39 + + 126.62 +
      + Jelly + + All Gender + + 74 + + 53.93 + + 135.03 +
      + Peanut Butter + + All Gender + + 64 + + 50.10 + + 126.71 +
      + BBB Best + + All Gender + + 14 + + 11.58 + + 27.40 +
      + CDR + + All Gender + + 17 + + 14.68 + + 41.25 +
      + Landslide + + All Gender + + 14 + + 6.62 + + 17.04 +
      + Plato + + All Gender + + 7 + + 6.91 + + 17.15 +
      + Super + + All Gender + + 12 + + 10.31 + + 23.87 +
      + Preserves + + All Gender + + 86 + + 57.99 + + 143.89 +
      + Breakfast Foods + + All Gender + + 80 + + 62.80 + + 154.04 +
      + Canned Foods + + All Gender + + 456 + + 361.79 + + 914.81 +
      + Canned Products + + All Gender + + 45 + + 39.72 + + 95.88 +
      + Dairy + + All Gender + + 283 + + 296.91 + + 722.75 +
      + Deli + + All Gender + + 252 + + 190.32 + + 479.59 +
      + Eggs + + All Gender + + 114 + + 104.65 + + 256.15 +
      + Frozen Foods + + All Gender + + 599 + + 490.33 + + 1,222.54 +
      + Meat + + All Gender + + 40 + + 31.66 + + 84.76 +
      + Produce + + All Gender + + 858 + + 752.62 + + 1,886.01 +
      + Seafood + + All Gender + + 27 + + 20.66 + + 50.39 +
      + Snack Foods + + All Gender + + 596 + + 555.70 + + 1,402.21 +
      + Snacks + + All Gender + + 147 + + 120.43 + + 304.18 +
      + Starchy Foods + + All Gender + + 108 + + 108.55 + + 271.69 +
      + Non-Consumable + + All Gender + + 1,115 + + 960.90 + + 2,388.79 +
      + Carousel + + All Gender + + 18 + + 10.99 + + 26.94 +
      + Checkout + + All Gender + + 26 + + 24.68 + + 62.14 +
      + Health and Hygiene + + All Gender + + 378 + + 309.37 + + 771.48 +
      + Household + + All Gender + + 585 + + 516.99 + + 1,276.16 +
      + Periodicals + + All Gender + + 108 + + 98.86 + + 252.07 +
      + Sunday Paper, Radio, TV + + All Products + + All Gender + + 2,726 + + 2,341.58 + + 5,819.33 +
      + Drink + + All Gender + + 225 + + 163.09 + + 403.51 +
      + Food + + All Gender + + 2,021 + + 1,762.18 + + 4,377.85 +
      + Baked Goods + + All Gender + + 67 + + 66.17 + + 163.29 +
      + Baking Goods + + All Gender + + 228 + + 182.98 + + 455.90 +
      + Baking Goods + + All Gender + + 90 + + 73.09 + + 176.63 +
      + Jams and Jellies + + All Gender + + 138 + + 109.90 + + 279.27 +
      + Jam + + All Gender + + 37 + + 31.30 + + 78.56 +
      + Jelly + + All Gender + + 27 + + 16.18 + + 39.92 +
      + Peanut Butter + + All Gender + + 30 + + 24.01 + + 64.19 +
      + BBB Best + + All Gender + + 11 + + 9.78 + + 23.86 +
      + CDR + + All Gender + +   + +   + +   +
      + Landslide + + All Gender + + 4 + + 2.39 + + 5.68 +
      + Plato + + All Gender + + 5 + + 3.85 + + 11.60 +
      + Super + + All Gender + + 10 + + 7.99 + + 23.05 +
      + Preserves + + All Gender + + 44 + + 38.41 + + 96.60 +
      + Breakfast Foods + + All Gender + + 38 + + 32.76 + + 89.85 +
      + Canned Foods + + All Gender + + 180 + + 138.77 + + 340.04 +
      + Canned Products + + All Gender + + 14 + + 12.00 + + 28.28 +
      + Dairy + + All Gender + + 121 + + 125.32 + + 305.43 +
      + Deli + + All Gender + + 131 + + 98.93 + + 245.42 +
      + Eggs + + All Gender + + 39 + + 39.57 + + 91.99 +
      + Frozen Foods + + All Gender + + 279 + + 207.59 + + 514.95 +
      + Meat + + All Gender + + 12 + + 11.77 + + 30.23 +
      + Produce + + All Gender + + 411 + + 382.14 + + 943.93 +
      + Seafood + + All Gender + + 31 + + 28.07 + + 69.82 +
      + Snack Foods + + All Gender + + 346 + + 318.26 + + 798.50 +
      + Snacks + + All Gender + + 75 + + 65.49 + + 174.02 +
      + Starchy Foods + + All Gender + + 49 + + 52.37 + + 126.20 +
      + Non-Consumable + + All Gender + + 480 + + 416.30 + + 1,037.97 +
      + Carousel + + All Gender + + 21 + + 11.63 + + 27.92 +
      + Checkout + + All Gender + + 10 + + 8.12 + + 19.80 +
      + Health and Hygiene + + All Gender + + 138 + + 110.35 + + 276.31 +
      + Household + + All Gender + + 262 + + 244.90 + + 608.52 +
      + Periodicals + + All Gender + + 49 + + 41.30 + + 105.42 +
      + TV + + All Products + + All Gender + + 3,607 + + 3,116.40 + + 7,786.21 +
      + Drink + + All Gender + + 332 + + 283.18 + + 721.07 +
      + Food + + All Gender + + 2,563 + + 2,238.13 + + 5,573.27 +
      + Baked Goods + + All Gender + + 114 + + 103.40 + + 262.97 +
      + Baking Goods + + All Gender + + 237 + + 185.55 + + 464.23 +
      + Baking Goods + + All Gender + + 95 + + 74.29 + + 190.59 +
      + Jams and Jellies + + All Gender + + 142 + + 111.25 + + 273.64 +
      + Jam + + All Gender + + 38 + + 32.28 + + 77.58 +
      + Jelly + + All Gender + + 35 + + 24.64 + + 63.38 +
      + Peanut Butter + + All Gender + + 31 + + 21.83 + + 56.80 +
      + BBB Best + + All Gender + +   + +   + +   +
      + CDR + + All Gender + + 11 + + 9.78 + + 27.19 +
      + Landslide + + All Gender + + 7 + + 2.61 + + 7.12 +
      + Plato + + All Gender + + 6 + + 4.95 + + 12.13 +
      + Super + + All Gender + + 7 + + 4.48 + + 10.36 +
      + Preserves + + All Gender + + 38 + + 32.51 + + 75.88 +
      + Breakfast Foods + + All Gender + + 36 + + 30.11 + + 79.89 +
      + Canned Foods + + All Gender + + 240 + + 200.00 + + 519.91 +
      + Canned Products + + All Gender + + 26 + + 15.00 + + 38.65 +
      + Dairy + + All Gender + + 179 + + 183.73 + + 458.87 +
      + Deli + + All Gender + + 155 + + 139.76 + + 342.51 +
      + Eggs + + All Gender + + 42 + + 32.74 + + 80.93 +
      + Frozen Foods + + All Gender + + 352 + + 300.42 + + 738.40 +
      + Meat + + All Gender + + 22 + + 19.76 + + 49.27 +
      + Produce + + All Gender + + 543 + + 456.53 + + 1,145.45 +
      + Seafood + + All Gender + + 34 + + 30.71 + + 75.47 +
      + Snack Foods + + All Gender + + 401 + + 377.01 + + 927.50 +
      + Snacks + + All Gender + + 99 + + 92.80 + + 220.54 +
      + Starchy Foods + + All Gender + + 83 + + 70.61 + + 168.68 +
      + Non-Consumable + + All Gender + + 712 + + 595.08 + + 1,491.87 +
      + Carousel + + All Gender + + 4 + + 3.13 + + 9.20 +
      + Checkout + + All Gender + + 34 + + 34.12 + + 86.21 +
      + Health and Hygiene + + All Gender + + 249 + + 196.08 + + 486.46 +
      + Household + + All Gender + + 361 + + 316.09 + + 795.40 +
      + Periodicals + + All Gender + + 64 + + 45.67 + + 114.60 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/insane-rows-false-false-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/insane-rows-false-false-true-result.html index 685cf0d2..23480092 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/insane-rows-false-false-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/insane-rows-false-false-true-result.html @@ -1,6971 +1,6971 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - All Products - - All Gender - - 266,773 - - 225,627.23 - - 565,238.13 -
      - All Products - - Drink - - All Gender - - 24,597 - - 19,477.23 - - 48,836.21 -
      - Food - - All Gender - - 191,940 - - 163,270.72 - - 409,035.59 -
      - Food - - Baked Goods - - All Gender - - 7,870 - - 6,564.09 - - 16,455.43 -
      - Baking Goods - - All Gender - - 20,245 - - 15,370.61 - - 38,670.41 -
      - Baking Goods - - Baking Goods - - All Gender - - 8,357 - - 6,123.32 - - 15,446.69 -
      - All Gender - - F - - 4,005 - - 2,907.70 - - 7,313.61 -
      - M - - 4,352 - - 3,215.62 - - 8,133.08 -
      - Jams and Jellies - - All Gender - - 11,888 - - 9,247.29 - - 23,223.72 -
      - Jams and Jellies - - Jam - - All Gender - - 2,556 - - 2,132.27 - - 5,401.81 -
      - Jelly - - All Gender - - 2,565 - - 1,830.04 - - 4,609.61 -
      - All Gender - - F - - 1,309 - - 956.94 - - 2,414.94 -
      - M - - 1,256 - - 873.10 - - 2,194.67 -
      - Peanut Butter - - All Gender - - 2,667 - - 2,097.37 - - 5,231.08 -
      - Peanut Butter - - BBB Best - - All Gender - - 556 - - 424.38 - - 1,055.72 -
      - All Gender - - F - - 271 - - 201.08 - - 500.39 -
      - M - - 285 - - 223.30 - - 555.33 -
      - BBB Best - - BBB Best Chunky Peanut Butter - - All Gender - - 188 - - 147.32 - - 370.36 -
      - All Gender - - F - - 107 - - 85.81 - - 210.79 -
      - M - - 81 - - 61.50 - - 159.57 -
      - BBB Best Creamy Peanut Butter - - All Gender - - 201 - - 87.86 - - 221.10 -
      - All Gender - - F - - 99 - - 43.35 - - 108.90 -
      - M - - 102 - - 44.51 - - 112.20 -
      - BBB Best Extra Chunky Peanut Butter - - All Gender - - 167 - - 189.21 - - 464.26 -
      - All Gender - - F - - 65 - - 71.92 - - 180.70 -
      - M - - 102 - - 117.29 - - 283.56 -
      - CDR - - All Gender - - 545 - - 538.88 - - 1,326.30 -
      - Landslide - - All Gender - - 531 - - 256.16 - - 635.29 -
      - Plato - - All Gender - - 520 - - 447.73 - - 1,132.16 -
      - Super - - All Gender - - 515 - - 430.21 - - 1,081.61 -
      - Preserves - - All Gender - - 4,100 - - 3,187.61 - - 7,981.22 -
      - All Gender - - F - - 1,946 - - 1,472.42 - - 3,717.80 -
      - M - - 2,154 - - 1,715.19 - - 4,263.42 -
      - Breakfast Foods - - All Gender - - 3,317 - - 2,756.80 - - 6,941.46 -
      - Canned Foods - - All Gender - - 19,026 - - 15,894.53 - - 39,774.34 -
      - Canned Foods - - Canned Anchovies - - All Gender - - 900 - - 913.88 - - 2,296.38 -
      - Canned Clams - - All Gender - - 882 - - 759.80 - - 1,912.68 -
      - Canned Clams - - Clams - - All Gender - - 882 - - 759.80 - - 1,912.68 -
      - Clams - - Better - - All Gender - - 189 - - 151.14 - - 398.79 -
      - Blue Label - - All Gender - - 165 - - 112.82 - - 278.85 -
      - Bravo - - All Gender - - 184 - - 280.70 - - 708.40 -
      - Just Right - - All Gender - - 177 - - 161.96 - - 394.71 -
      - Pleasant - - All Gender - - 167 - - 53.17 - - 131.93 -
      - Canned Oysters - - All Gender - - 708 - - 571.50 - - 1,442.77 -
      - Canned Sardines - - All Gender - - 819 - - 537.59 - - 1,357.80 -
      - Canned Shrimp - - All Gender - - 804 - - 858.39 - - 2,146.49 -
      - Canned Soup - - All Gender - - 8,006 - - 6,408.29 - - 15,966.10 -
      - Canned Tuna - - All Gender - - 1,710 - - 1,288.52 - - 3,210.76 -
      - Vegetables - - All Gender - - 5,197 - - 4,556.57 - - 11,441.36 -
      - Canned Products - - All Gender - - 1,812 - - 1,317.13 - - 3,314.52 -
      - Dairy - - All Gender - - 12,885 - - 12,228.85 - - 30,508.85 -
      - Deli - - All Gender - - 12,037 - - 10,108.87 - - 25,318.93 -
      - Deli - - Meat - - All Gender - - 9,433 - - 8,215.81 - - 20,616.29 -
      - Meat - - Bologna - - All Gender - - 2,588 - - 2,340.24 - - 5,859.95 -
      - Deli Meats - - All Gender - - 3,339 - - 2,851.18 - - 7,191.24 -
      - All Gender - - F - - 1,653 - - 1,414.49 - - 3,579.34 -
      - M - - 1,686 - - 1,436.69 - - 3,611.90 -
      - Fresh Chicken - - All Gender - - 878 - - 842.85 - - 2,091.52 -
      - Hot Dogs - - All Gender - - 2,628 - - 2,181.55 - - 5,473.58 -
      - Side Dishes - - All Gender - - 2,604 - - 1,893.06 - - 4,702.64 -
      - Eggs - - All Gender - - 4,132 - - 3,684.90 - - 9,200.76 -
      - Frozen Foods - - All Gender - - 26,655 - - 22,030.66 - - 55,207.50 -
      - Meat - - All Gender - - 1,714 - - 1,465.42 - - 3,669.89 -
      - Produce - - All Gender - - 37,792 - - 32,831.33 - - 82,248.42 -
      - Seafood - - All Gender - - 1,764 - - 1,520.70 - - 3,809.14 -
      - Snack Foods - - All Gender - - 30,545 - - 26,963.34 - - 67,609.82 -
      - Snacks - - All Gender - - 6,884 - - 5,827.58 - - 14,550.05 -
      - Starchy Foods - - All Gender - - 5,262 - - 4,705.91 - - 11,756.07 -
      - Non-Consumable - - All Gender - - 50,236 - - 42,879.28 - - 107,366.33 -
      - Non-Consumable - - Carousel - - All Gender - - 841 - - 595.97 - - 1,500.11 -
      - Checkout - - All Gender - - 1,779 - - 1,525.04 - - 3,767.71 -
      - Health and Hygiene - - All Gender - - 16,284 - - 12,972.99 - - 32,571.86 -
      - Household - - All Gender - - 27,038 - - 24,170.73 - - 60,469.89 -
      - Periodicals - - All Gender - - 4,294 - - 3,614.55 - - 9,056.76 -
      - All Media - - Bulk Mail - - All Products - - All Gender - - 4,320 - - 3,740.95 - - 9,349.07 -
      - Cash Register Handout - - All Products - - All Gender - - 6,697 - - 5,715.67 - - 14,321.33 -
      - Daily Paper - - All Products - - All Gender - - 7,738 - - 6,559.23 - - 16,479.81 -
      - Daily Paper, Radio - - All Products - - All Gender - - 6,891 - - 5,668.77 - - 14,169.42 -
      - Daily Paper, Radio, TV - - All Products - - All Gender - - 9,513 - - 8,055.22 - - 20,173.97 -
      - In-Store Coupon - - All Products - - All Gender - - 3,798 - - 3,263.11 - - 8,162.46 -
      - All Products - - Drink - - All Gender - - 345 - - 282.44 - - 708.38 -
      - Food - - All Gender - - 2,737 - - 2,345.57 - - 5,889.34 -
      - Food - - Baked Goods - - All Gender - - 131 - - 114.11 - - 279.11 -
      - Baking Goods - - All Gender - - 308 - - 252.88 - - 632.01 -
      - Baking Goods - - Baking Goods - - All Gender - - 146 - - 103.30 - - 261.44 -
      - Jams and Jellies - - All Gender - - 162 - - 149.58 - - 370.57 -
      - Jams and Jellies - - Jam - - All Gender - - 55 - - 58.16 - - 141.19 -
      - Jelly - - All Gender - - 32 - - 23.96 - - 62.12 -
      - Peanut Butter - - All Gender - - 22 - - 19.54 - - 48.72 -
      - Peanut Butter - - BBB Best - - All Gender - - 7 - - 6.72 - - 16.10 -
      - CDR - - All Gender - - 10 - - 9.81 - - 24.32 -
      - Landslide - - All Gender - -   - -   - -   -
      - Plato - - All Gender - - 3 - - 2.32 - - 6.32 -
      - Super - - All Gender - - 2 - - .69 - - 1.98 -
      - Preserves - - All Gender - - 53 - - 47.92 - - 118.54 -
      - Breakfast Foods - - All Gender - - 59 - - 49.22 - - 125.19 -
      - All Gender - - F - - 33 - - 22.88 - - 54.84 -
      - M - - 26 - - 26.34 - - 70.35 -
      - Canned Foods - - All Gender - - 245 - - 200.61 - - 506.67 -
      - Canned Products - - All Gender - - 15 - - 9.58 - - 26.17 -
      - Dairy - - All Gender - - 166 - - 153.42 - - 372.01 -
      - Deli - - All Gender - - 180 - - 163.58 - - 392.68 -
      - Eggs - - All Gender - - 56 - - 42.51 - - 108.90 -
      - Frozen Foods - - All Gender - - 374 - - 301.63 - - 773.52 -
      - Meat - - All Gender - - 31 - - 23.91 - - 70.35 -
      - Produce - - All Gender - - 563 - - 499.63 - - 1,257.05 -
      - Seafood - - All Gender - - 34 - - 30.06 - - 76.09 -
      - Snack Foods - - All Gender - - 439 - - 390.35 - - 989.13 -
      - Snacks - - All Gender - - 78 - - 63.77 - - 153.02 -
      - Starchy Foods - - All Gender - - 58 - - 50.30 - - 127.44 -
      - Non-Consumable - - All Gender - - 716 - - 635.10 - - 1,564.74 -
      - Non-Consumable - - Carousel - - All Gender - - 17 - - 8.77 - - 24.18 -
      - Checkout - - All Gender - - 23 - - 15.20 - - 40.19 -
      - Health and Hygiene - - All Gender - - 251 - - 193.53 - - 477.21 -
      - Household - - All Gender - - 374 - - 375.66 - - 916.97 -
      - Periodicals - - All Gender - - 51 - - 41.94 - - 106.19 -
      - No Media - - All Products - - All Gender - - 195,448 - - 165,214.85 - - 414,026.92 -
      - All Products - - Drink - - All Gender - - 17,896 - - 14,211.41 - - 35,681.85 -
      - Food - - All Gender - - 140,577 - - 119,469.36 - - 299,356.11 -
      - Food - - Baked Goods - - All Gender - - 5,753 - - 4,775.86 - - 11,972.46 -
      - Baking Goods - - All Gender - - 14,849 - - 11,226.15 - - 28,312.78 -
      - Baking Goods - - Baking Goods - - All Gender - - 5,979 - - 4,347.34 - - 11,002.73 -
      - Jams and Jellies - - All Gender - - 8,870 - - 6,878.81 - - 17,310.05 -
      - Jams and Jellies - - Jam - - All Gender - - 1,883 - - 1,554.13 - - 3,965.74 -
      - Jelly - - All Gender - - 1,936 - - 1,394.32 - - 3,504.71 -
      - Peanut Butter - - All Gender - - 1,984 - - 1,534.19 - - 3,828.01 -
      - Peanut Butter - - BBB Best - - All Gender - - 406 - - 293.97 - - 735.29 -
      - CDR - - All Gender - - 411 - - 401.88 - - 998.12 -
      - Landslide - - All Gender - - 401 - - 195.51 - - 478.44 -
      - Plato - - All Gender - - 384 - - 331.26 - - 832.92 -
      - Super - - All Gender - - 382 - - 311.57 - - 783.24 -
      - Preserves - - All Gender - - 3,067 - - 2,396.16 - - 6,011.59 -
      - Breakfast Foods - - All Gender - - 2,418 - - 1,996.45 - - 5,016.10 -
      - Canned Foods - - All Gender - - 13,861 - - 11,647.47 - - 29,102.79 -
      - Canned Products - - All Gender - - 1,344 - - 960.82 - - 2,424.98 -
      - Dairy - - All Gender - - 9,510 - - 8,981.13 - - 22,454.02 -
      - Deli - - All Gender - - 8,695 - - 7,353.56 - - 18,410.26 -
      - Eggs - - All Gender - - 2,976 - - 2,640.47 - - 6,606.25 -
      - Frozen Foods - - All Gender - - 19,450 - - 16,127.24 - - 40,411.08 -
      - Meat - - All Gender - - 1,236 - - 1,068.07 - - 2,646.00 -
      - Produce - - All Gender - - 27,637 - - 24,036.36 - - 60,203.58 -
      - Seafood - - All Gender - - 1,292 - - 1,114.69 - - 2,774.43 -
      - Snack Foods - - All Gender - - 22,525 - - 19,800.82 - - 49,680.71 -
      - Snacks - - All Gender - - 5,100 - - 4,264.55 - - 10,690.26 -
      - Starchy Foods - - All Gender - - 3,931 - - 3,475.74 - - 8,650.41 -
      - Non-Consumable - - All Gender - - 36,975 - - 31,534.08 - - 78,988.96 -
      - Non-Consumable - - Carousel - - All Gender - - 584 - - 419.65 - - 1,050.75 -
      - Checkout - - All Gender - - 1,305 - - 1,113.97 - - 2,768.66 -
      - Health and Hygiene - - All Gender - - 11,845 - - 9,413.25 - - 23,621.12 -
      - Household - - All Gender - - 20,091 - - 17,929.20 - - 44,881.13 -
      - Periodicals - - All Gender - - 3,150 - - 2,658.00 - - 6,667.30 -
      - Product Attachment - - All Products - - All Gender - - 7,544 - - 6,306.24 - - 15,898.25 -
      - All Products - - Drink - - All Gender - - 713 - - 555.05 - - 1,403.65 -
      - Food - - All Gender - - 5,441 - - 4,571.71 - - 11,525.25 -
      - Food - - Baked Goods - - All Gender - - 213 - - 175.69 - - 445.60 -
      - Baking Goods - - All Gender - - 547 - - 410.31 - - 1,032.59 -
      - Baking Goods - - Baking Goods - - All Gender - - 258 - - 191.48 - - 470.58 -
      - Jams and Jellies - - All Gender - - 289 - - 218.83 - - 562.01 -
      - Jams and Jellies - - Jam - - All Gender - - 66 - - 48.03 - - 128.68 -
      - Jelly - - All Gender - - 45 - - 34.12 - - 90.62 -
      - Peanut Butter - - All Gender - - 63 - - 47.71 - - 122.31 -
      - Peanut Butter - - BBB Best - - All Gender - - 15 - - 14.53 - - 38.46 -
      - CDR - - All Gender - - 13 - - 11.94 - - 30.57 -
      - Landslide - - All Gender - - 12 - - 5.32 - - 14.28 -
      - Plato - - All Gender - - 9 - - 7.16 - - 17.43 -
      - Super - - All Gender - - 14 - - 8.75 - - 21.57 -
      - Preserves - - All Gender - - 115 - - 88.98 - - 220.40 -
      - Breakfast Foods - - All Gender - - 103 - - 87.35 - - 220.75 -
      - Canned Foods - - All Gender - - 564 - - 463.28 - - 1,154.91 -
      - Canned Products - - All Gender - - 60 - - 51.61 - - 124.24 -
      - Dairy - - All Gender - - 355 - - 339.81 - - 849.78 -
      - Deli - - All Gender - - 324 - - 243.64 - - 618.23 -
      - Eggs - - All Gender - - 118 - - 97.43 - - 241.21 -
      - Frozen Foods - - All Gender - - 812 - - 665.48 - - 1,692.11 -
      - Meat - - All Gender - - 54 - - 51.36 - - 127.83 -
      - Produce - - All Gender - - 1,069 - - 909.24 - - 2,287.61 -
      - Seafood - - All Gender - - 45 - - 36.98 - - 100.61 -
      - Snack Foods - - All Gender - - 819 - - 726.73 - - 1,847.28 -
      - Snacks - - All Gender - - 209 - - 186.22 - - 450.03 -
      - Starchy Foods - - All Gender - - 149 - - 126.59 - - 332.47 -
      - Non-Consumable - - All Gender - - 1,390 - - 1,179.48 - - 2,969.35 -
      - Non-Consumable - - Carousel - - All Gender - - 14 - - 7.99 - - 21.21 -
      - Checkout - - All Gender - - 48 - - 40.45 - - 100.61 -
      - Health and Hygiene - - All Gender - - 440 - - 356.54 - - 901.73 -
      - Household - - All Gender - - 777 - - 690.03 - - 1,737.96 -
      - Periodicals - - All Gender - - 111 - - 84.48 - - 207.84 -
      - Radio - - All Products - - All Gender - - 2,454 - - 2,087.51 - - 5,213.61 -
      - All Products - - Drink - - All Gender - - 226 - - 182.85 - - 443.68 -
      - Food - - All Gender - - 1,733 - - 1,485.25 - - 3,727.36 -
      - Food - - Baked Goods - - All Gender - - 83 - - 76.51 - - 186.20 -
      - Baking Goods - - All Gender - - 157 - - 109.10 - - 274.90 -
      - Baking Goods - - Baking Goods - - All Gender - - 63 - - 45.02 - - 110.43 -
      - Jams and Jellies - - All Gender - - 94 - - 64.08 - - 164.47 -
      - Jams and Jellies - - Jam - - All Gender - - 15 - - 10.42 - - 26.94 -
      - Jelly - - All Gender - - 24 - - 14.54 - - 37.49 -
      - Peanut Butter - - All Gender - - 19 - - 16.85 - - 41.82 -
      - Peanut Butter - - BBB Best - - All Gender - - 10 - - 10.58 - - 24.44 -
      - CDR - - All Gender - -   - -   - -   -
      - Landslide - - All Gender - -   - -   - -   -
      - Plato - - All Gender - - 4 - - 3.77 - - 9.80 -
      - Super - - All Gender - - 5 - - 2.50 - - 7.58 -
      - Preserves - - All Gender - - 36 - - 22.28 - - 58.22 -
      - Breakfast Foods - - All Gender - - 25 - - 18.78 - - 50.22 -
      - Canned Foods - - All Gender - - 158 - - 124.79 - - 307.55 -
      - Canned Products - - All Gender - - 22 - - 17.29 - - 43.42 -
      - Dairy - - All Gender - - 112 - - 92.12 - - 216.79 -
      - Deli - - All Gender - - 129 - - 119.14 - - 307.25 -
      - Eggs - - All Gender - - 25 - - 29.97 - - 71.15 -
      - Frozen Foods - - All Gender - - 253 - - 202.71 - - 507.45 -
      - Meat - - All Gender - - 12 - - 11.53 - - 32.85 -
      - Produce - - All Gender - - 336 - - 292.05 - - 738.20 -
      - Seafood - - All Gender - - 15 - - 13.28 - - 35.58 -
      - Snack Foods - - All Gender - - 290 - - 270.59 - - 674.73 -
      - Snacks - - All Gender - - 60 - - 55.67 - - 144.58 -
      - Starchy Foods - - All Gender - - 56 - - 51.72 - - 136.49 -
      - Non-Consumable - - All Gender - - 495 - - 419.41 - - 1,042.57 -
      - Non-Consumable - - Carousel - - All Gender - - 15 - - 11.15 - - 26.85 -
      - Checkout - - All Gender - - 21 - - 17.00 - - 42.74 -
      - Health and Hygiene - - All Gender - - 145 - - 114.84 - - 289.80 -
      - Household - - All Gender - - 258 - - 233.31 - - 575.07 -
      - Periodicals - - All Gender - - 56 - - 43.12 - - 108.11 -
      - Street Handout - - All Products - - All Gender - - 5,753 - - 4,856.54 - - 12,192.90 -
      - All Products - - Drink - - All Gender - - 512 - - 372.68 - - 943.42 -
      - Food - - All Gender - - 4,239 - - 3,650.32 - - 9,151.65 -
      - Food - - Baked Goods - - All Gender - - 160 - - 120.12 - - 301.62 -
      - Baking Goods - - All Gender - - 498 - - 373.67 - - 923.22 -
      - Baking Goods - - Baking Goods - - All Gender - - 200 - - 144.16 - - 357.82 -
      - Jams and Jellies - - All Gender - - 298 - - 229.51 - - 565.40 -
      - Jams and Jellies - - Jam - - All Gender - - 53 - - 44.30 - - 112.95 -
      - Jelly - - All Gender - - 92 - - 63.14 - - 155.59 -
      - Peanut Butter - - All Gender - - 51 - - 51.06 - - 118.90 -
      - Peanut Butter - - BBB Best - - All Gender - - 11 - - 10.85 - - 25.72 -
      - CDR - - All Gender - - 8 - - 9.06 - - 19.73 -
      - Landslide - - All Gender - - 11 - - 6.90 - - 15.54 -
      - Plato - - All Gender - - 9 - - 8.47 - - 20.89 -
      - Super - - All Gender - - 12 - - 15.78 - - 37.02 -
      - Preserves - - All Gender - - 102 - - 71.02 - - 177.96 -
      - Breakfast Foods - - All Gender - - 81 - - 74.32 - - 192.90 -
      - Canned Foods - - All Gender - - 459 - - 413.21 - - 1,021.86 -
      - Canned Products - - All Gender - - 30 - - 19.43 - - 45.68 -
      - Dairy - - All Gender - - 301 - - 285.98 - - 718.61 -
      - Deli - - All Gender - - 305 - - 253.54 - - 638.30 -
      - Eggs - - All Gender - - 66 - - 59.15 - - 156.82 -
      - Frozen Foods - - All Gender - - 612 - - 520.12 - - 1,313.71 -
      - Meat - - All Gender - - 37 - - 29.82 - - 78.24 -
      - Produce - - All Gender - - 745 - - 662.39 - - 1,639.94 -
      - Seafood - - All Gender - - 37 - - 30.12 - - 72.77 -
      - Snack Foods - - All Gender - - 675 - - 600.23 - - 1,515.68 -
      - Snacks - - All Gender - - 144 - - 128.79 - - 321.16 -
      - Starchy Foods - - All Gender - - 89 - - 79.43 - - 211.14 -
      - Non-Consumable - - All Gender - - 1,002 - - 833.53 - - 2,097.83 -
      - Non-Consumable - - Carousel - - All Gender - - 17 - - 13.53 - - 30.98 -
      - Checkout - - All Gender - - 45 - - 34.77 - - 85.38 -
      - Health and Hygiene - - All Gender - - 402 - - 318.03 - - 802.92 -
      - Household - - All Gender - - 501 - - 436.41 - - 1,105.38 -
      - Periodicals - - All Gender - - 37 - - 30.80 - - 73.17 -
      - Sunday Paper - - All Products - - All Gender - - 4,339 - - 3,673.86 - - 9,092.89 -
      - All Products - - Drink - - All Gender - - 430 - - 345.53 - - 856.73 -
      - Food - - All Gender - - 3,106 - - 2,646.47 - - 6,559.46 -
      - Food - - Baked Goods - - All Gender - - 140 - - 110.79 - - 282.55 -
      - Baking Goods - - All Gender - - 338 - - 239.76 - - 603.86 -
      - Baking Goods - - Baking Goods - - All Gender - - 170 - - 118.05 - - 298.79 -
      - Jams and Jellies - - All Gender - - 168 - - 121.71 - - 305.07 -
      - Jams and Jellies - - Jam - - All Gender - - 24 - - 22.35 - - 54.83 -
      - Jelly - - All Gender - - 27 - - 18.20 - - 47.12 -
      - Peanut Butter - - All Gender - - 51 - - 37.67 - - 96.67 -
      - Peanut Butter - - BBB Best - - All Gender - - 10 - - 6.08 - - 16.22 -
      - CDR - - All Gender - - 10 - - 10.47 - - 26.50 -
      - Landslide - - All Gender - - 15 - - 6.20 - - 16.31 -
      - Plato - - All Gender - - 16 - - 14.93 - - 37.64 -
      - Super - - All Gender - -   - -   - -   -
      - Preserves - - All Gender - - 66 - - 43.49 - - 106.45 -
      - Breakfast Foods - - All Gender - - 55 - - 49.80 - - 120.23 -
      - Canned Foods - - All Gender - - 283 - - 249.46 - - 605.11 -
      - Canned Products - - All Gender - - 34 - - 29.65 - - 72.18 -
      - Dairy - - All Gender - - 200 - - 201.94 - - 497.91 -
      - Deli - - All Gender - - 228 - - 188.37 - - 467.53 -
      - Eggs - - All Gender - - 54 - - 47.68 - - 118.44 -
      - Frozen Foods - - All Gender - - 425 - - 330.81 - - 839.15 -
      - Meat - - All Gender - - 18 - - 19.85 - - 52.20 -
      - Produce - - All Gender - - 603 - - 520.95 - - 1,274.70 -
      - Seafood - - All Gender - - 27 - - 26.82 - - 69.49 -
      - Snack Foods - - All Gender - - 469 - - 413.18 - - 1,027.98 -
      - Snacks - - All Gender - - 123 - - 108.50 - - 261.38 -
      - Starchy Foods - - All Gender - - 109 - - 108.91 - - 266.75 -
      - Non-Consumable - - All Gender - - 803 - - 681.86 - - 1,676.70 -
      - Non-Consumable - - Carousel - - All Gender - - 7 - - 6.70 - - 14.68 -
      - Checkout - - All Gender - - 17 - - 13.09 - - 30.89 -
      - Health and Hygiene - - All Gender - - 278 - - 227.06 - - 565.99 -
      - Household - - All Gender - - 420 - - 371.58 - - 911.69 -
      - Periodicals - - All Gender - - 81 - - 63.43 - - 153.45 -
      - Sunday Paper, Radio - - All Products - - All Gender - - 5,945 - - 5,027.31 - - 12,551.96 -
      - All Products - - Drink - - All Gender - - 591 - - 454.03 - - 1,129.94 -
      - Food - - All Gender - - 4,239 - - 3,612.38 - - 9,033.23 -
      - Food - - Baked Goods - - All Gender - - 152 - - 109.11 - - 274.39 -
      - Baking Goods - - All Gender - - 482 - - 367.13 - - 913.84 -
      - Baking Goods - - Baking Goods - - All Gender - - 206 - - 152.72 - - 381.59 -
      - Jams and Jellies - - All Gender - - 276 - - 214.41 - - 532.25 -
      - Jams and Jellies - - Jam - - All Gender - - 52 - - 52.39 - - 126.62 -
      - Jelly - - All Gender - - 74 - - 53.93 - - 135.03 -
      - Peanut Butter - - All Gender - - 64 - - 50.10 - - 126.71 -
      - Peanut Butter - - BBB Best - - All Gender - - 14 - - 11.58 - - 27.40 -
      - CDR - - All Gender - - 17 - - 14.68 - - 41.25 -
      - Landslide - - All Gender - - 14 - - 6.62 - - 17.04 -
      - Plato - - All Gender - - 7 - - 6.91 - - 17.15 -
      - Super - - All Gender - - 12 - - 10.31 - - 23.87 -
      - Preserves - - All Gender - - 86 - - 57.99 - - 143.89 -
      - Breakfast Foods - - All Gender - - 80 - - 62.80 - - 154.04 -
      - Canned Foods - - All Gender - - 456 - - 361.79 - - 914.81 -
      - Canned Products - - All Gender - - 45 - - 39.72 - - 95.88 -
      - Dairy - - All Gender - - 283 - - 296.91 - - 722.75 -
      - Deli - - All Gender - - 252 - - 190.32 - - 479.59 -
      - Eggs - - All Gender - - 114 - - 104.65 - - 256.15 -
      - Frozen Foods - - All Gender - - 599 - - 490.33 - - 1,222.54 -
      - Meat - - All Gender - - 40 - - 31.66 - - 84.76 -
      - Produce - - All Gender - - 858 - - 752.62 - - 1,886.01 -
      - Seafood - - All Gender - - 27 - - 20.66 - - 50.39 -
      - Snack Foods - - All Gender - - 596 - - 555.70 - - 1,402.21 -
      - Snacks - - All Gender - - 147 - - 120.43 - - 304.18 -
      - Starchy Foods - - All Gender - - 108 - - 108.55 - - 271.69 -
      - Non-Consumable - - All Gender - - 1,115 - - 960.90 - - 2,388.79 -
      - Non-Consumable - - Carousel - - All Gender - - 18 - - 10.99 - - 26.94 -
      - Checkout - - All Gender - - 26 - - 24.68 - - 62.14 -
      - Health and Hygiene - - All Gender - - 378 - - 309.37 - - 771.48 -
      - Household - - All Gender - - 585 - - 516.99 - - 1,276.16 -
      - Periodicals - - All Gender - - 108 - - 98.86 - - 252.07 -
      - Sunday Paper, Radio, TV - - All Products - - All Gender - - 2,726 - - 2,341.58 - - 5,819.33 -
      - All Products - - Drink - - All Gender - - 225 - - 163.09 - - 403.51 -
      - Food - - All Gender - - 2,021 - - 1,762.18 - - 4,377.85 -
      - Food - - Baked Goods - - All Gender - - 67 - - 66.17 - - 163.29 -
      - Baking Goods - - All Gender - - 228 - - 182.98 - - 455.90 -
      - Baking Goods - - Baking Goods - - All Gender - - 90 - - 73.09 - - 176.63 -
      - Jams and Jellies - - All Gender - - 138 - - 109.90 - - 279.27 -
      - Jams and Jellies - - Jam - - All Gender - - 37 - - 31.30 - - 78.56 -
      - Jelly - - All Gender - - 27 - - 16.18 - - 39.92 -
      - Peanut Butter - - All Gender - - 30 - - 24.01 - - 64.19 -
      - Peanut Butter - - BBB Best - - All Gender - - 11 - - 9.78 - - 23.86 -
      - CDR - - All Gender - -   - -   - -   -
      - Landslide - - All Gender - - 4 - - 2.39 - - 5.68 -
      - Plato - - All Gender - - 5 - - 3.85 - - 11.60 -
      - Super - - All Gender - - 10 - - 7.99 - - 23.05 -
      - Preserves - - All Gender - - 44 - - 38.41 - - 96.60 -
      - Breakfast Foods - - All Gender - - 38 - - 32.76 - - 89.85 -
      - Canned Foods - - All Gender - - 180 - - 138.77 - - 340.04 -
      - Canned Products - - All Gender - - 14 - - 12.00 - - 28.28 -
      - Dairy - - All Gender - - 121 - - 125.32 - - 305.43 -
      - Deli - - All Gender - - 131 - - 98.93 - - 245.42 -
      - Eggs - - All Gender - - 39 - - 39.57 - - 91.99 -
      - Frozen Foods - - All Gender - - 279 - - 207.59 - - 514.95 -
      - Meat - - All Gender - - 12 - - 11.77 - - 30.23 -
      - Produce - - All Gender - - 411 - - 382.14 - - 943.93 -
      - Seafood - - All Gender - - 31 - - 28.07 - - 69.82 -
      - Snack Foods - - All Gender - - 346 - - 318.26 - - 798.50 -
      - Snacks - - All Gender - - 75 - - 65.49 - - 174.02 -
      - Starchy Foods - - All Gender - - 49 - - 52.37 - - 126.20 -
      - Non-Consumable - - All Gender - - 480 - - 416.30 - - 1,037.97 -
      - Non-Consumable - - Carousel - - All Gender - - 21 - - 11.63 - - 27.92 -
      - Checkout - - All Gender - - 10 - - 8.12 - - 19.80 -
      - Health and Hygiene - - All Gender - - 138 - - 110.35 - - 276.31 -
      - Household - - All Gender - - 262 - - 244.90 - - 608.52 -
      - Periodicals - - All Gender - - 49 - - 41.30 - - 105.42 -
      - TV - - All Products - - All Gender - - 3,607 - - 3,116.40 - - 7,786.21 -
      - All Products - - Drink - - All Gender - - 332 - - 283.18 - - 721.07 -
      - Food - - All Gender - - 2,563 - - 2,238.13 - - 5,573.27 -
      - Food - - Baked Goods - - All Gender - - 114 - - 103.40 - - 262.97 -
      - Baking Goods - - All Gender - - 237 - - 185.55 - - 464.23 -
      - Baking Goods - - Baking Goods - - All Gender - - 95 - - 74.29 - - 190.59 -
      - Jams and Jellies - - All Gender - - 142 - - 111.25 - - 273.64 -
      - Jams and Jellies - - Jam - - All Gender - - 38 - - 32.28 - - 77.58 -
      - Jelly - - All Gender - - 35 - - 24.64 - - 63.38 -
      - Peanut Butter - - All Gender - - 31 - - 21.83 - - 56.80 -
      - Peanut Butter - - BBB Best - - All Gender - -   - -   - -   -
      - CDR - - All Gender - - 11 - - 9.78 - - 27.19 -
      - Landslide - - All Gender - - 7 - - 2.61 - - 7.12 -
      - Plato - - All Gender - - 6 - - 4.95 - - 12.13 -
      - Super - - All Gender - - 7 - - 4.48 - - 10.36 -
      - Preserves - - All Gender - - 38 - - 32.51 - - 75.88 -
      - Breakfast Foods - - All Gender - - 36 - - 30.11 - - 79.89 -
      - Canned Foods - - All Gender - - 240 - - 200.00 - - 519.91 -
      - Canned Products - - All Gender - - 26 - - 15.00 - - 38.65 -
      - Dairy - - All Gender - - 179 - - 183.73 - - 458.87 -
      - Deli - - All Gender - - 155 - - 139.76 - - 342.51 -
      - Eggs - - All Gender - - 42 - - 32.74 - - 80.93 -
      - Frozen Foods - - All Gender - - 352 - - 300.42 - - 738.40 -
      - Meat - - All Gender - - 22 - - 19.76 - - 49.27 -
      - Produce - - All Gender - - 543 - - 456.53 - - 1,145.45 -
      - Seafood - - All Gender - - 34 - - 30.71 - - 75.47 -
      - Snack Foods - - All Gender - - 401 - - 377.01 - - 927.50 -
      - Snacks - - All Gender - - 99 - - 92.80 - - 220.54 -
      - Starchy Foods - - All Gender - - 83 - - 70.61 - - 168.68 -
      - Non-Consumable - - All Gender - - 712 - - 595.08 - - 1,491.87 -
      - Non-Consumable - - Carousel - - All Gender - - 4 - - 3.13 - - 9.20 -
      - Checkout - - All Gender - - 34 - - 34.12 - - 86.21 -
      - Health and Hygiene - - All Gender - - 249 - - 196.08 - - 486.46 -
      - Household - - All Gender - - 361 - - 316.09 - - 795.40 -
      - Periodicals - - All Gender - - 64 - - 45.67 - - 114.60 -
      +   + + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + All Products + + All Gender + + 266,773 + + 225,627.23 + + 565,238.13 +
      + All Products + + Drink + + All Gender + + 24,597 + + 19,477.23 + + 48,836.21 +
      + Food + + All Gender + + 191,940 + + 163,270.72 + + 409,035.59 +
      + Food + + Baked Goods + + All Gender + + 7,870 + + 6,564.09 + + 16,455.43 +
      + Baking Goods + + All Gender + + 20,245 + + 15,370.61 + + 38,670.41 +
      + Baking Goods + + Baking Goods + + All Gender + + 8,357 + + 6,123.32 + + 15,446.69 +
      + All Gender + + F + + 4,005 + + 2,907.70 + + 7,313.61 +
      + M + + 4,352 + + 3,215.62 + + 8,133.08 +
      + Jams and Jellies + + All Gender + + 11,888 + + 9,247.29 + + 23,223.72 +
      + Jams and Jellies + + Jam + + All Gender + + 2,556 + + 2,132.27 + + 5,401.81 +
      + Jelly + + All Gender + + 2,565 + + 1,830.04 + + 4,609.61 +
      + All Gender + + F + + 1,309 + + 956.94 + + 2,414.94 +
      + M + + 1,256 + + 873.10 + + 2,194.67 +
      + Peanut Butter + + All Gender + + 2,667 + + 2,097.37 + + 5,231.08 +
      + Peanut Butter + + BBB Best + + All Gender + + 556 + + 424.38 + + 1,055.72 +
      + All Gender + + F + + 271 + + 201.08 + + 500.39 +
      + M + + 285 + + 223.30 + + 555.33 +
      + BBB Best + + BBB Best Chunky Peanut Butter + + All Gender + + 188 + + 147.32 + + 370.36 +
      + All Gender + + F + + 107 + + 85.81 + + 210.79 +
      + M + + 81 + + 61.50 + + 159.57 +
      + BBB Best Creamy Peanut Butter + + All Gender + + 201 + + 87.86 + + 221.10 +
      + All Gender + + F + + 99 + + 43.35 + + 108.90 +
      + M + + 102 + + 44.51 + + 112.20 +
      + BBB Best Extra Chunky Peanut Butter + + All Gender + + 167 + + 189.21 + + 464.26 +
      + All Gender + + F + + 65 + + 71.92 + + 180.70 +
      + M + + 102 + + 117.29 + + 283.56 +
      + CDR + + All Gender + + 545 + + 538.88 + + 1,326.30 +
      + Landslide + + All Gender + + 531 + + 256.16 + + 635.29 +
      + Plato + + All Gender + + 520 + + 447.73 + + 1,132.16 +
      + Super + + All Gender + + 515 + + 430.21 + + 1,081.61 +
      + Preserves + + All Gender + + 4,100 + + 3,187.61 + + 7,981.22 +
      + All Gender + + F + + 1,946 + + 1,472.42 + + 3,717.80 +
      + M + + 2,154 + + 1,715.19 + + 4,263.42 +
      + Breakfast Foods + + All Gender + + 3,317 + + 2,756.80 + + 6,941.46 +
      + Canned Foods + + All Gender + + 19,026 + + 15,894.53 + + 39,774.34 +
      + Canned Foods + + Canned Anchovies + + All Gender + + 900 + + 913.88 + + 2,296.38 +
      + Canned Clams + + All Gender + + 882 + + 759.80 + + 1,912.68 +
      + Canned Clams + + Clams + + All Gender + + 882 + + 759.80 + + 1,912.68 +
      + Clams + + Better + + All Gender + + 189 + + 151.14 + + 398.79 +
      + Blue Label + + All Gender + + 165 + + 112.82 + + 278.85 +
      + Bravo + + All Gender + + 184 + + 280.70 + + 708.40 +
      + Just Right + + All Gender + + 177 + + 161.96 + + 394.71 +
      + Pleasant + + All Gender + + 167 + + 53.17 + + 131.93 +
      + Canned Oysters + + All Gender + + 708 + + 571.50 + + 1,442.77 +
      + Canned Sardines + + All Gender + + 819 + + 537.59 + + 1,357.80 +
      + Canned Shrimp + + All Gender + + 804 + + 858.39 + + 2,146.49 +
      + Canned Soup + + All Gender + + 8,006 + + 6,408.29 + + 15,966.10 +
      + Canned Tuna + + All Gender + + 1,710 + + 1,288.52 + + 3,210.76 +
      + Vegetables + + All Gender + + 5,197 + + 4,556.57 + + 11,441.36 +
      + Canned Products + + All Gender + + 1,812 + + 1,317.13 + + 3,314.52 +
      + Dairy + + All Gender + + 12,885 + + 12,228.85 + + 30,508.85 +
      + Deli + + All Gender + + 12,037 + + 10,108.87 + + 25,318.93 +
      + Deli + + Meat + + All Gender + + 9,433 + + 8,215.81 + + 20,616.29 +
      + Meat + + Bologna + + All Gender + + 2,588 + + 2,340.24 + + 5,859.95 +
      + Deli Meats + + All Gender + + 3,339 + + 2,851.18 + + 7,191.24 +
      + All Gender + + F + + 1,653 + + 1,414.49 + + 3,579.34 +
      + M + + 1,686 + + 1,436.69 + + 3,611.90 +
      + Fresh Chicken + + All Gender + + 878 + + 842.85 + + 2,091.52 +
      + Hot Dogs + + All Gender + + 2,628 + + 2,181.55 + + 5,473.58 +
      + Side Dishes + + All Gender + + 2,604 + + 1,893.06 + + 4,702.64 +
      + Eggs + + All Gender + + 4,132 + + 3,684.90 + + 9,200.76 +
      + Frozen Foods + + All Gender + + 26,655 + + 22,030.66 + + 55,207.50 +
      + Meat + + All Gender + + 1,714 + + 1,465.42 + + 3,669.89 +
      + Produce + + All Gender + + 37,792 + + 32,831.33 + + 82,248.42 +
      + Seafood + + All Gender + + 1,764 + + 1,520.70 + + 3,809.14 +
      + Snack Foods + + All Gender + + 30,545 + + 26,963.34 + + 67,609.82 +
      + Snacks + + All Gender + + 6,884 + + 5,827.58 + + 14,550.05 +
      + Starchy Foods + + All Gender + + 5,262 + + 4,705.91 + + 11,756.07 +
      + Non-Consumable + + All Gender + + 50,236 + + 42,879.28 + + 107,366.33 +
      + Non-Consumable + + Carousel + + All Gender + + 841 + + 595.97 + + 1,500.11 +
      + Checkout + + All Gender + + 1,779 + + 1,525.04 + + 3,767.71 +
      + Health and Hygiene + + All Gender + + 16,284 + + 12,972.99 + + 32,571.86 +
      + Household + + All Gender + + 27,038 + + 24,170.73 + + 60,469.89 +
      + Periodicals + + All Gender + + 4,294 + + 3,614.55 + + 9,056.76 +
      + All Media + + Bulk Mail + + All Products + + All Gender + + 4,320 + + 3,740.95 + + 9,349.07 +
      + Cash Register Handout + + All Products + + All Gender + + 6,697 + + 5,715.67 + + 14,321.33 +
      + Daily Paper + + All Products + + All Gender + + 7,738 + + 6,559.23 + + 16,479.81 +
      + Daily Paper, Radio + + All Products + + All Gender + + 6,891 + + 5,668.77 + + 14,169.42 +
      + Daily Paper, Radio, TV + + All Products + + All Gender + + 9,513 + + 8,055.22 + + 20,173.97 +
      + In-Store Coupon + + All Products + + All Gender + + 3,798 + + 3,263.11 + + 8,162.46 +
      + All Products + + Drink + + All Gender + + 345 + + 282.44 + + 708.38 +
      + Food + + All Gender + + 2,737 + + 2,345.57 + + 5,889.34 +
      + Food + + Baked Goods + + All Gender + + 131 + + 114.11 + + 279.11 +
      + Baking Goods + + All Gender + + 308 + + 252.88 + + 632.01 +
      + Baking Goods + + Baking Goods + + All Gender + + 146 + + 103.30 + + 261.44 +
      + Jams and Jellies + + All Gender + + 162 + + 149.58 + + 370.57 +
      + Jams and Jellies + + Jam + + All Gender + + 55 + + 58.16 + + 141.19 +
      + Jelly + + All Gender + + 32 + + 23.96 + + 62.12 +
      + Peanut Butter + + All Gender + + 22 + + 19.54 + + 48.72 +
      + Peanut Butter + + BBB Best + + All Gender + + 7 + + 6.72 + + 16.10 +
      + CDR + + All Gender + + 10 + + 9.81 + + 24.32 +
      + Landslide + + All Gender + +   + +   + +   +
      + Plato + + All Gender + + 3 + + 2.32 + + 6.32 +
      + Super + + All Gender + + 2 + + .69 + + 1.98 +
      + Preserves + + All Gender + + 53 + + 47.92 + + 118.54 +
      + Breakfast Foods + + All Gender + + 59 + + 49.22 + + 125.19 +
      + All Gender + + F + + 33 + + 22.88 + + 54.84 +
      + M + + 26 + + 26.34 + + 70.35 +
      + Canned Foods + + All Gender + + 245 + + 200.61 + + 506.67 +
      + Canned Products + + All Gender + + 15 + + 9.58 + + 26.17 +
      + Dairy + + All Gender + + 166 + + 153.42 + + 372.01 +
      + Deli + + All Gender + + 180 + + 163.58 + + 392.68 +
      + Eggs + + All Gender + + 56 + + 42.51 + + 108.90 +
      + Frozen Foods + + All Gender + + 374 + + 301.63 + + 773.52 +
      + Meat + + All Gender + + 31 + + 23.91 + + 70.35 +
      + Produce + + All Gender + + 563 + + 499.63 + + 1,257.05 +
      + Seafood + + All Gender + + 34 + + 30.06 + + 76.09 +
      + Snack Foods + + All Gender + + 439 + + 390.35 + + 989.13 +
      + Snacks + + All Gender + + 78 + + 63.77 + + 153.02 +
      + Starchy Foods + + All Gender + + 58 + + 50.30 + + 127.44 +
      + Non-Consumable + + All Gender + + 716 + + 635.10 + + 1,564.74 +
      + Non-Consumable + + Carousel + + All Gender + + 17 + + 8.77 + + 24.18 +
      + Checkout + + All Gender + + 23 + + 15.20 + + 40.19 +
      + Health and Hygiene + + All Gender + + 251 + + 193.53 + + 477.21 +
      + Household + + All Gender + + 374 + + 375.66 + + 916.97 +
      + Periodicals + + All Gender + + 51 + + 41.94 + + 106.19 +
      + No Media + + All Products + + All Gender + + 195,448 + + 165,214.85 + + 414,026.92 +
      + All Products + + Drink + + All Gender + + 17,896 + + 14,211.41 + + 35,681.85 +
      + Food + + All Gender + + 140,577 + + 119,469.36 + + 299,356.11 +
      + Food + + Baked Goods + + All Gender + + 5,753 + + 4,775.86 + + 11,972.46 +
      + Baking Goods + + All Gender + + 14,849 + + 11,226.15 + + 28,312.78 +
      + Baking Goods + + Baking Goods + + All Gender + + 5,979 + + 4,347.34 + + 11,002.73 +
      + Jams and Jellies + + All Gender + + 8,870 + + 6,878.81 + + 17,310.05 +
      + Jams and Jellies + + Jam + + All Gender + + 1,883 + + 1,554.13 + + 3,965.74 +
      + Jelly + + All Gender + + 1,936 + + 1,394.32 + + 3,504.71 +
      + Peanut Butter + + All Gender + + 1,984 + + 1,534.19 + + 3,828.01 +
      + Peanut Butter + + BBB Best + + All Gender + + 406 + + 293.97 + + 735.29 +
      + CDR + + All Gender + + 411 + + 401.88 + + 998.12 +
      + Landslide + + All Gender + + 401 + + 195.51 + + 478.44 +
      + Plato + + All Gender + + 384 + + 331.26 + + 832.92 +
      + Super + + All Gender + + 382 + + 311.57 + + 783.24 +
      + Preserves + + All Gender + + 3,067 + + 2,396.16 + + 6,011.59 +
      + Breakfast Foods + + All Gender + + 2,418 + + 1,996.45 + + 5,016.10 +
      + Canned Foods + + All Gender + + 13,861 + + 11,647.47 + + 29,102.79 +
      + Canned Products + + All Gender + + 1,344 + + 960.82 + + 2,424.98 +
      + Dairy + + All Gender + + 9,510 + + 8,981.13 + + 22,454.02 +
      + Deli + + All Gender + + 8,695 + + 7,353.56 + + 18,410.26 +
      + Eggs + + All Gender + + 2,976 + + 2,640.47 + + 6,606.25 +
      + Frozen Foods + + All Gender + + 19,450 + + 16,127.24 + + 40,411.08 +
      + Meat + + All Gender + + 1,236 + + 1,068.07 + + 2,646.00 +
      + Produce + + All Gender + + 27,637 + + 24,036.36 + + 60,203.58 +
      + Seafood + + All Gender + + 1,292 + + 1,114.69 + + 2,774.43 +
      + Snack Foods + + All Gender + + 22,525 + + 19,800.82 + + 49,680.71 +
      + Snacks + + All Gender + + 5,100 + + 4,264.55 + + 10,690.26 +
      + Starchy Foods + + All Gender + + 3,931 + + 3,475.74 + + 8,650.41 +
      + Non-Consumable + + All Gender + + 36,975 + + 31,534.08 + + 78,988.96 +
      + Non-Consumable + + Carousel + + All Gender + + 584 + + 419.65 + + 1,050.75 +
      + Checkout + + All Gender + + 1,305 + + 1,113.97 + + 2,768.66 +
      + Health and Hygiene + + All Gender + + 11,845 + + 9,413.25 + + 23,621.12 +
      + Household + + All Gender + + 20,091 + + 17,929.20 + + 44,881.13 +
      + Periodicals + + All Gender + + 3,150 + + 2,658.00 + + 6,667.30 +
      + Product Attachment + + All Products + + All Gender + + 7,544 + + 6,306.24 + + 15,898.25 +
      + All Products + + Drink + + All Gender + + 713 + + 555.05 + + 1,403.65 +
      + Food + + All Gender + + 5,441 + + 4,571.71 + + 11,525.25 +
      + Food + + Baked Goods + + All Gender + + 213 + + 175.69 + + 445.60 +
      + Baking Goods + + All Gender + + 547 + + 410.31 + + 1,032.59 +
      + Baking Goods + + Baking Goods + + All Gender + + 258 + + 191.48 + + 470.58 +
      + Jams and Jellies + + All Gender + + 289 + + 218.83 + + 562.01 +
      + Jams and Jellies + + Jam + + All Gender + + 66 + + 48.03 + + 128.68 +
      + Jelly + + All Gender + + 45 + + 34.12 + + 90.62 +
      + Peanut Butter + + All Gender + + 63 + + 47.71 + + 122.31 +
      + Peanut Butter + + BBB Best + + All Gender + + 15 + + 14.53 + + 38.46 +
      + CDR + + All Gender + + 13 + + 11.94 + + 30.57 +
      + Landslide + + All Gender + + 12 + + 5.32 + + 14.28 +
      + Plato + + All Gender + + 9 + + 7.16 + + 17.43 +
      + Super + + All Gender + + 14 + + 8.75 + + 21.57 +
      + Preserves + + All Gender + + 115 + + 88.98 + + 220.40 +
      + Breakfast Foods + + All Gender + + 103 + + 87.35 + + 220.75 +
      + Canned Foods + + All Gender + + 564 + + 463.28 + + 1,154.91 +
      + Canned Products + + All Gender + + 60 + + 51.61 + + 124.24 +
      + Dairy + + All Gender + + 355 + + 339.81 + + 849.78 +
      + Deli + + All Gender + + 324 + + 243.64 + + 618.23 +
      + Eggs + + All Gender + + 118 + + 97.43 + + 241.21 +
      + Frozen Foods + + All Gender + + 812 + + 665.48 + + 1,692.11 +
      + Meat + + All Gender + + 54 + + 51.36 + + 127.83 +
      + Produce + + All Gender + + 1,069 + + 909.24 + + 2,287.61 +
      + Seafood + + All Gender + + 45 + + 36.98 + + 100.61 +
      + Snack Foods + + All Gender + + 819 + + 726.73 + + 1,847.28 +
      + Snacks + + All Gender + + 209 + + 186.22 + + 450.03 +
      + Starchy Foods + + All Gender + + 149 + + 126.59 + + 332.47 +
      + Non-Consumable + + All Gender + + 1,390 + + 1,179.48 + + 2,969.35 +
      + Non-Consumable + + Carousel + + All Gender + + 14 + + 7.99 + + 21.21 +
      + Checkout + + All Gender + + 48 + + 40.45 + + 100.61 +
      + Health and Hygiene + + All Gender + + 440 + + 356.54 + + 901.73 +
      + Household + + All Gender + + 777 + + 690.03 + + 1,737.96 +
      + Periodicals + + All Gender + + 111 + + 84.48 + + 207.84 +
      + Radio + + All Products + + All Gender + + 2,454 + + 2,087.51 + + 5,213.61 +
      + All Products + + Drink + + All Gender + + 226 + + 182.85 + + 443.68 +
      + Food + + All Gender + + 1,733 + + 1,485.25 + + 3,727.36 +
      + Food + + Baked Goods + + All Gender + + 83 + + 76.51 + + 186.20 +
      + Baking Goods + + All Gender + + 157 + + 109.10 + + 274.90 +
      + Baking Goods + + Baking Goods + + All Gender + + 63 + + 45.02 + + 110.43 +
      + Jams and Jellies + + All Gender + + 94 + + 64.08 + + 164.47 +
      + Jams and Jellies + + Jam + + All Gender + + 15 + + 10.42 + + 26.94 +
      + Jelly + + All Gender + + 24 + + 14.54 + + 37.49 +
      + Peanut Butter + + All Gender + + 19 + + 16.85 + + 41.82 +
      + Peanut Butter + + BBB Best + + All Gender + + 10 + + 10.58 + + 24.44 +
      + CDR + + All Gender + +   + +   + +   +
      + Landslide + + All Gender + +   + +   + +   +
      + Plato + + All Gender + + 4 + + 3.77 + + 9.80 +
      + Super + + All Gender + + 5 + + 2.50 + + 7.58 +
      + Preserves + + All Gender + + 36 + + 22.28 + + 58.22 +
      + Breakfast Foods + + All Gender + + 25 + + 18.78 + + 50.22 +
      + Canned Foods + + All Gender + + 158 + + 124.79 + + 307.55 +
      + Canned Products + + All Gender + + 22 + + 17.29 + + 43.42 +
      + Dairy + + All Gender + + 112 + + 92.12 + + 216.79 +
      + Deli + + All Gender + + 129 + + 119.14 + + 307.25 +
      + Eggs + + All Gender + + 25 + + 29.97 + + 71.15 +
      + Frozen Foods + + All Gender + + 253 + + 202.71 + + 507.45 +
      + Meat + + All Gender + + 12 + + 11.53 + + 32.85 +
      + Produce + + All Gender + + 336 + + 292.05 + + 738.20 +
      + Seafood + + All Gender + + 15 + + 13.28 + + 35.58 +
      + Snack Foods + + All Gender + + 290 + + 270.59 + + 674.73 +
      + Snacks + + All Gender + + 60 + + 55.67 + + 144.58 +
      + Starchy Foods + + All Gender + + 56 + + 51.72 + + 136.49 +
      + Non-Consumable + + All Gender + + 495 + + 419.41 + + 1,042.57 +
      + Non-Consumable + + Carousel + + All Gender + + 15 + + 11.15 + + 26.85 +
      + Checkout + + All Gender + + 21 + + 17.00 + + 42.74 +
      + Health and Hygiene + + All Gender + + 145 + + 114.84 + + 289.80 +
      + Household + + All Gender + + 258 + + 233.31 + + 575.07 +
      + Periodicals + + All Gender + + 56 + + 43.12 + + 108.11 +
      + Street Handout + + All Products + + All Gender + + 5,753 + + 4,856.54 + + 12,192.90 +
      + All Products + + Drink + + All Gender + + 512 + + 372.68 + + 943.42 +
      + Food + + All Gender + + 4,239 + + 3,650.32 + + 9,151.65 +
      + Food + + Baked Goods + + All Gender + + 160 + + 120.12 + + 301.62 +
      + Baking Goods + + All Gender + + 498 + + 373.67 + + 923.22 +
      + Baking Goods + + Baking Goods + + All Gender + + 200 + + 144.16 + + 357.82 +
      + Jams and Jellies + + All Gender + + 298 + + 229.51 + + 565.40 +
      + Jams and Jellies + + Jam + + All Gender + + 53 + + 44.30 + + 112.95 +
      + Jelly + + All Gender + + 92 + + 63.14 + + 155.59 +
      + Peanut Butter + + All Gender + + 51 + + 51.06 + + 118.90 +
      + Peanut Butter + + BBB Best + + All Gender + + 11 + + 10.85 + + 25.72 +
      + CDR + + All Gender + + 8 + + 9.06 + + 19.73 +
      + Landslide + + All Gender + + 11 + + 6.90 + + 15.54 +
      + Plato + + All Gender + + 9 + + 8.47 + + 20.89 +
      + Super + + All Gender + + 12 + + 15.78 + + 37.02 +
      + Preserves + + All Gender + + 102 + + 71.02 + + 177.96 +
      + Breakfast Foods + + All Gender + + 81 + + 74.32 + + 192.90 +
      + Canned Foods + + All Gender + + 459 + + 413.21 + + 1,021.86 +
      + Canned Products + + All Gender + + 30 + + 19.43 + + 45.68 +
      + Dairy + + All Gender + + 301 + + 285.98 + + 718.61 +
      + Deli + + All Gender + + 305 + + 253.54 + + 638.30 +
      + Eggs + + All Gender + + 66 + + 59.15 + + 156.82 +
      + Frozen Foods + + All Gender + + 612 + + 520.12 + + 1,313.71 +
      + Meat + + All Gender + + 37 + + 29.82 + + 78.24 +
      + Produce + + All Gender + + 745 + + 662.39 + + 1,639.94 +
      + Seafood + + All Gender + + 37 + + 30.12 + + 72.77 +
      + Snack Foods + + All Gender + + 675 + + 600.23 + + 1,515.68 +
      + Snacks + + All Gender + + 144 + + 128.79 + + 321.16 +
      + Starchy Foods + + All Gender + + 89 + + 79.43 + + 211.14 +
      + Non-Consumable + + All Gender + + 1,002 + + 833.53 + + 2,097.83 +
      + Non-Consumable + + Carousel + + All Gender + + 17 + + 13.53 + + 30.98 +
      + Checkout + + All Gender + + 45 + + 34.77 + + 85.38 +
      + Health and Hygiene + + All Gender + + 402 + + 318.03 + + 802.92 +
      + Household + + All Gender + + 501 + + 436.41 + + 1,105.38 +
      + Periodicals + + All Gender + + 37 + + 30.80 + + 73.17 +
      + Sunday Paper + + All Products + + All Gender + + 4,339 + + 3,673.86 + + 9,092.89 +
      + All Products + + Drink + + All Gender + + 430 + + 345.53 + + 856.73 +
      + Food + + All Gender + + 3,106 + + 2,646.47 + + 6,559.46 +
      + Food + + Baked Goods + + All Gender + + 140 + + 110.79 + + 282.55 +
      + Baking Goods + + All Gender + + 338 + + 239.76 + + 603.86 +
      + Baking Goods + + Baking Goods + + All Gender + + 170 + + 118.05 + + 298.79 +
      + Jams and Jellies + + All Gender + + 168 + + 121.71 + + 305.07 +
      + Jams and Jellies + + Jam + + All Gender + + 24 + + 22.35 + + 54.83 +
      + Jelly + + All Gender + + 27 + + 18.20 + + 47.12 +
      + Peanut Butter + + All Gender + + 51 + + 37.67 + + 96.67 +
      + Peanut Butter + + BBB Best + + All Gender + + 10 + + 6.08 + + 16.22 +
      + CDR + + All Gender + + 10 + + 10.47 + + 26.50 +
      + Landslide + + All Gender + + 15 + + 6.20 + + 16.31 +
      + Plato + + All Gender + + 16 + + 14.93 + + 37.64 +
      + Super + + All Gender + +   + +   + +   +
      + Preserves + + All Gender + + 66 + + 43.49 + + 106.45 +
      + Breakfast Foods + + All Gender + + 55 + + 49.80 + + 120.23 +
      + Canned Foods + + All Gender + + 283 + + 249.46 + + 605.11 +
      + Canned Products + + All Gender + + 34 + + 29.65 + + 72.18 +
      + Dairy + + All Gender + + 200 + + 201.94 + + 497.91 +
      + Deli + + All Gender + + 228 + + 188.37 + + 467.53 +
      + Eggs + + All Gender + + 54 + + 47.68 + + 118.44 +
      + Frozen Foods + + All Gender + + 425 + + 330.81 + + 839.15 +
      + Meat + + All Gender + + 18 + + 19.85 + + 52.20 +
      + Produce + + All Gender + + 603 + + 520.95 + + 1,274.70 +
      + Seafood + + All Gender + + 27 + + 26.82 + + 69.49 +
      + Snack Foods + + All Gender + + 469 + + 413.18 + + 1,027.98 +
      + Snacks + + All Gender + + 123 + + 108.50 + + 261.38 +
      + Starchy Foods + + All Gender + + 109 + + 108.91 + + 266.75 +
      + Non-Consumable + + All Gender + + 803 + + 681.86 + + 1,676.70 +
      + Non-Consumable + + Carousel + + All Gender + + 7 + + 6.70 + + 14.68 +
      + Checkout + + All Gender + + 17 + + 13.09 + + 30.89 +
      + Health and Hygiene + + All Gender + + 278 + + 227.06 + + 565.99 +
      + Household + + All Gender + + 420 + + 371.58 + + 911.69 +
      + Periodicals + + All Gender + + 81 + + 63.43 + + 153.45 +
      + Sunday Paper, Radio + + All Products + + All Gender + + 5,945 + + 5,027.31 + + 12,551.96 +
      + All Products + + Drink + + All Gender + + 591 + + 454.03 + + 1,129.94 +
      + Food + + All Gender + + 4,239 + + 3,612.38 + + 9,033.23 +
      + Food + + Baked Goods + + All Gender + + 152 + + 109.11 + + 274.39 +
      + Baking Goods + + All Gender + + 482 + + 367.13 + + 913.84 +
      + Baking Goods + + Baking Goods + + All Gender + + 206 + + 152.72 + + 381.59 +
      + Jams and Jellies + + All Gender + + 276 + + 214.41 + + 532.25 +
      + Jams and Jellies + + Jam + + All Gender + + 52 + + 52.39 + + 126.62 +
      + Jelly + + All Gender + + 74 + + 53.93 + + 135.03 +
      + Peanut Butter + + All Gender + + 64 + + 50.10 + + 126.71 +
      + Peanut Butter + + BBB Best + + All Gender + + 14 + + 11.58 + + 27.40 +
      + CDR + + All Gender + + 17 + + 14.68 + + 41.25 +
      + Landslide + + All Gender + + 14 + + 6.62 + + 17.04 +
      + Plato + + All Gender + + 7 + + 6.91 + + 17.15 +
      + Super + + All Gender + + 12 + + 10.31 + + 23.87 +
      + Preserves + + All Gender + + 86 + + 57.99 + + 143.89 +
      + Breakfast Foods + + All Gender + + 80 + + 62.80 + + 154.04 +
      + Canned Foods + + All Gender + + 456 + + 361.79 + + 914.81 +
      + Canned Products + + All Gender + + 45 + + 39.72 + + 95.88 +
      + Dairy + + All Gender + + 283 + + 296.91 + + 722.75 +
      + Deli + + All Gender + + 252 + + 190.32 + + 479.59 +
      + Eggs + + All Gender + + 114 + + 104.65 + + 256.15 +
      + Frozen Foods + + All Gender + + 599 + + 490.33 + + 1,222.54 +
      + Meat + + All Gender + + 40 + + 31.66 + + 84.76 +
      + Produce + + All Gender + + 858 + + 752.62 + + 1,886.01 +
      + Seafood + + All Gender + + 27 + + 20.66 + + 50.39 +
      + Snack Foods + + All Gender + + 596 + + 555.70 + + 1,402.21 +
      + Snacks + + All Gender + + 147 + + 120.43 + + 304.18 +
      + Starchy Foods + + All Gender + + 108 + + 108.55 + + 271.69 +
      + Non-Consumable + + All Gender + + 1,115 + + 960.90 + + 2,388.79 +
      + Non-Consumable + + Carousel + + All Gender + + 18 + + 10.99 + + 26.94 +
      + Checkout + + All Gender + + 26 + + 24.68 + + 62.14 +
      + Health and Hygiene + + All Gender + + 378 + + 309.37 + + 771.48 +
      + Household + + All Gender + + 585 + + 516.99 + + 1,276.16 +
      + Periodicals + + All Gender + + 108 + + 98.86 + + 252.07 +
      + Sunday Paper, Radio, TV + + All Products + + All Gender + + 2,726 + + 2,341.58 + + 5,819.33 +
      + All Products + + Drink + + All Gender + + 225 + + 163.09 + + 403.51 +
      + Food + + All Gender + + 2,021 + + 1,762.18 + + 4,377.85 +
      + Food + + Baked Goods + + All Gender + + 67 + + 66.17 + + 163.29 +
      + Baking Goods + + All Gender + + 228 + + 182.98 + + 455.90 +
      + Baking Goods + + Baking Goods + + All Gender + + 90 + + 73.09 + + 176.63 +
      + Jams and Jellies + + All Gender + + 138 + + 109.90 + + 279.27 +
      + Jams and Jellies + + Jam + + All Gender + + 37 + + 31.30 + + 78.56 +
      + Jelly + + All Gender + + 27 + + 16.18 + + 39.92 +
      + Peanut Butter + + All Gender + + 30 + + 24.01 + + 64.19 +
      + Peanut Butter + + BBB Best + + All Gender + + 11 + + 9.78 + + 23.86 +
      + CDR + + All Gender + +   + +   + +   +
      + Landslide + + All Gender + + 4 + + 2.39 + + 5.68 +
      + Plato + + All Gender + + 5 + + 3.85 + + 11.60 +
      + Super + + All Gender + + 10 + + 7.99 + + 23.05 +
      + Preserves + + All Gender + + 44 + + 38.41 + + 96.60 +
      + Breakfast Foods + + All Gender + + 38 + + 32.76 + + 89.85 +
      + Canned Foods + + All Gender + + 180 + + 138.77 + + 340.04 +
      + Canned Products + + All Gender + + 14 + + 12.00 + + 28.28 +
      + Dairy + + All Gender + + 121 + + 125.32 + + 305.43 +
      + Deli + + All Gender + + 131 + + 98.93 + + 245.42 +
      + Eggs + + All Gender + + 39 + + 39.57 + + 91.99 +
      + Frozen Foods + + All Gender + + 279 + + 207.59 + + 514.95 +
      + Meat + + All Gender + + 12 + + 11.77 + + 30.23 +
      + Produce + + All Gender + + 411 + + 382.14 + + 943.93 +
      + Seafood + + All Gender + + 31 + + 28.07 + + 69.82 +
      + Snack Foods + + All Gender + + 346 + + 318.26 + + 798.50 +
      + Snacks + + All Gender + + 75 + + 65.49 + + 174.02 +
      + Starchy Foods + + All Gender + + 49 + + 52.37 + + 126.20 +
      + Non-Consumable + + All Gender + + 480 + + 416.30 + + 1,037.97 +
      + Non-Consumable + + Carousel + + All Gender + + 21 + + 11.63 + + 27.92 +
      + Checkout + + All Gender + + 10 + + 8.12 + + 19.80 +
      + Health and Hygiene + + All Gender + + 138 + + 110.35 + + 276.31 +
      + Household + + All Gender + + 262 + + 244.90 + + 608.52 +
      + Periodicals + + All Gender + + 49 + + 41.30 + + 105.42 +
      + TV + + All Products + + All Gender + + 3,607 + + 3,116.40 + + 7,786.21 +
      + All Products + + Drink + + All Gender + + 332 + + 283.18 + + 721.07 +
      + Food + + All Gender + + 2,563 + + 2,238.13 + + 5,573.27 +
      + Food + + Baked Goods + + All Gender + + 114 + + 103.40 + + 262.97 +
      + Baking Goods + + All Gender + + 237 + + 185.55 + + 464.23 +
      + Baking Goods + + Baking Goods + + All Gender + + 95 + + 74.29 + + 190.59 +
      + Jams and Jellies + + All Gender + + 142 + + 111.25 + + 273.64 +
      + Jams and Jellies + + Jam + + All Gender + + 38 + + 32.28 + + 77.58 +
      + Jelly + + All Gender + + 35 + + 24.64 + + 63.38 +
      + Peanut Butter + + All Gender + + 31 + + 21.83 + + 56.80 +
      + Peanut Butter + + BBB Best + + All Gender + +   + +   + +   +
      + CDR + + All Gender + + 11 + + 9.78 + + 27.19 +
      + Landslide + + All Gender + + 7 + + 2.61 + + 7.12 +
      + Plato + + All Gender + + 6 + + 4.95 + + 12.13 +
      + Super + + All Gender + + 7 + + 4.48 + + 10.36 +
      + Preserves + + All Gender + + 38 + + 32.51 + + 75.88 +
      + Breakfast Foods + + All Gender + + 36 + + 30.11 + + 79.89 +
      + Canned Foods + + All Gender + + 240 + + 200.00 + + 519.91 +
      + Canned Products + + All Gender + + 26 + + 15.00 + + 38.65 +
      + Dairy + + All Gender + + 179 + + 183.73 + + 458.87 +
      + Deli + + All Gender + + 155 + + 139.76 + + 342.51 +
      + Eggs + + All Gender + + 42 + + 32.74 + + 80.93 +
      + Frozen Foods + + All Gender + + 352 + + 300.42 + + 738.40 +
      + Meat + + All Gender + + 22 + + 19.76 + + 49.27 +
      + Produce + + All Gender + + 543 + + 456.53 + + 1,145.45 +
      + Seafood + + All Gender + + 34 + + 30.71 + + 75.47 +
      + Snack Foods + + All Gender + + 401 + + 377.01 + + 927.50 +
      + Snacks + + All Gender + + 99 + + 92.80 + + 220.54 +
      + Starchy Foods + + All Gender + + 83 + + 70.61 + + 168.68 +
      + Non-Consumable + + All Gender + + 712 + + 595.08 + + 1,491.87 +
      + Non-Consumable + + Carousel + + All Gender + + 4 + + 3.13 + + 9.20 +
      + Checkout + + All Gender + + 34 + + 34.12 + + 86.21 +
      + Health and Hygiene + + All Gender + + 249 + + 196.08 + + 486.46 +
      + Household + + All Gender + + 361 + + 316.09 + + 795.40 +
      + Periodicals + + All Gender + + 64 + + 45.67 + + 114.60 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/insane-rows-false-true-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/insane-rows-false-true-false-result.html index 1bb75cc8..fdc76304 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/insane-rows-false-true-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/insane-rows-false-true-false-result.html @@ -1,6757 +1,6757 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Measures -
      - Promotion Media - - Product - - Gender - - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - All Products - - All Gender - - 266,773 - - 225,627.23 - - 565,238.13 -
      - Drink - - All Gender - - 24,597 - - 19,477.23 - - 48,836.21 -
      - Food - - All Gender - - 191,940 - - 163,270.72 - - 409,035.59 -
      - Baked Goods - - All Gender - - 7,870 - - 6,564.09 - - 16,455.43 -
      - Baking Goods - - All Gender - - 20,245 - - 15,370.61 - - 38,670.41 -
      - Baking Goods - - All Gender - - 8,357 - - 6,123.32 - - 15,446.69 -
      - F - - 4,005 - - 2,907.70 - - 7,313.61 -
      - M - - 4,352 - - 3,215.62 - - 8,133.08 -
      - Jams and Jellies - - All Gender - - 11,888 - - 9,247.29 - - 23,223.72 -
      - Jam - - All Gender - - 2,556 - - 2,132.27 - - 5,401.81 -
      - Jelly - - All Gender - - 2,565 - - 1,830.04 - - 4,609.61 -
      - F - - 1,309 - - 956.94 - - 2,414.94 -
      - M - - 1,256 - - 873.10 - - 2,194.67 -
      - Peanut Butter - - All Gender - - 2,667 - - 2,097.37 - - 5,231.08 -
      - BBB Best - - All Gender - - 556 - - 424.38 - - 1,055.72 -
      - F - - 271 - - 201.08 - - 500.39 -
      - M - - 285 - - 223.30 - - 555.33 -
      - BBB Best Chunky Peanut Butter - - All Gender - - 188 - - 147.32 - - 370.36 -
      - F - - 107 - - 85.81 - - 210.79 -
      - M - - 81 - - 61.50 - - 159.57 -
      - BBB Best Creamy Peanut Butter - - All Gender - - 201 - - 87.86 - - 221.10 -
      - F - - 99 - - 43.35 - - 108.90 -
      - M - - 102 - - 44.51 - - 112.20 -
      - BBB Best Extra Chunky Peanut Butter - - All Gender - - 167 - - 189.21 - - 464.26 -
      - F - - 65 - - 71.92 - - 180.70 -
      - M - - 102 - - 117.29 - - 283.56 -
      - CDR - - All Gender - - 545 - - 538.88 - - 1,326.30 -
      - Landslide - - All Gender - - 531 - - 256.16 - - 635.29 -
      - Plato - - All Gender - - 520 - - 447.73 - - 1,132.16 -
      - Super - - All Gender - - 515 - - 430.21 - - 1,081.61 -
      - Preserves - - All Gender - - 4,100 - - 3,187.61 - - 7,981.22 -
      - F - - 1,946 - - 1,472.42 - - 3,717.80 -
      - M - - 2,154 - - 1,715.19 - - 4,263.42 -
      - Breakfast Foods - - All Gender - - 3,317 - - 2,756.80 - - 6,941.46 -
      - Canned Foods - - All Gender - - 19,026 - - 15,894.53 - - 39,774.34 -
      - Canned Anchovies - - All Gender - - 900 - - 913.88 - - 2,296.38 -
      - Canned Clams - - All Gender - - 882 - - 759.80 - - 1,912.68 -
      - Clams - - All Gender - - 882 - - 759.80 - - 1,912.68 -
      - Better - - All Gender - - 189 - - 151.14 - - 398.79 -
      - Blue Label - - All Gender - - 165 - - 112.82 - - 278.85 -
      - Bravo - - All Gender - - 184 - - 280.70 - - 708.40 -
      - Just Right - - All Gender - - 177 - - 161.96 - - 394.71 -
      - Pleasant - - All Gender - - 167 - - 53.17 - - 131.93 -
      - Canned Oysters - - All Gender - - 708 - - 571.50 - - 1,442.77 -
      - Canned Sardines - - All Gender - - 819 - - 537.59 - - 1,357.80 -
      - Canned Shrimp - - All Gender - - 804 - - 858.39 - - 2,146.49 -
      - Canned Soup - - All Gender - - 8,006 - - 6,408.29 - - 15,966.10 -
      - Canned Tuna - - All Gender - - 1,710 - - 1,288.52 - - 3,210.76 -
      - Vegetables - - All Gender - - 5,197 - - 4,556.57 - - 11,441.36 -
      - Canned Products - - All Gender - - 1,812 - - 1,317.13 - - 3,314.52 -
      - Dairy - - All Gender - - 12,885 - - 12,228.85 - - 30,508.85 -
      - Deli - - All Gender - - 12,037 - - 10,108.87 - - 25,318.93 -
      - Meat - - All Gender - - 9,433 - - 8,215.81 - - 20,616.29 -
      - Bologna - - All Gender - - 2,588 - - 2,340.24 - - 5,859.95 -
      - Deli Meats - - All Gender - - 3,339 - - 2,851.18 - - 7,191.24 -
      - F - - 1,653 - - 1,414.49 - - 3,579.34 -
      - M - - 1,686 - - 1,436.69 - - 3,611.90 -
      - Fresh Chicken - - All Gender - - 878 - - 842.85 - - 2,091.52 -
      - Hot Dogs - - All Gender - - 2,628 - - 2,181.55 - - 5,473.58 -
      - Side Dishes - - All Gender - - 2,604 - - 1,893.06 - - 4,702.64 -
      - Eggs - - All Gender - - 4,132 - - 3,684.90 - - 9,200.76 -
      - Frozen Foods - - All Gender - - 26,655 - - 22,030.66 - - 55,207.50 -
      - Meat - - All Gender - - 1,714 - - 1,465.42 - - 3,669.89 -
      - Produce - - All Gender - - 37,792 - - 32,831.33 - - 82,248.42 -
      - Seafood - - All Gender - - 1,764 - - 1,520.70 - - 3,809.14 -
      - Snack Foods - - All Gender - - 30,545 - - 26,963.34 - - 67,609.82 -
      - Snacks - - All Gender - - 6,884 - - 5,827.58 - - 14,550.05 -
      - Starchy Foods - - All Gender - - 5,262 - - 4,705.91 - - 11,756.07 -
      - Non-Consumable - - All Gender - - 50,236 - - 42,879.28 - - 107,366.33 -
      - Carousel - - All Gender - - 841 - - 595.97 - - 1,500.11 -
      - Checkout - - All Gender - - 1,779 - - 1,525.04 - - 3,767.71 -
      - Health and Hygiene - - All Gender - - 16,284 - - 12,972.99 - - 32,571.86 -
      - Household - - All Gender - - 27,038 - - 24,170.73 - - 60,469.89 -
      - Periodicals - - All Gender - - 4,294 - - 3,614.55 - - 9,056.76 -
      - Bulk Mail - - All Products - - All Gender - - 4,320 - - 3,740.95 - - 9,349.07 -
      - Cash Register Handout - - All Products - - All Gender - - 6,697 - - 5,715.67 - - 14,321.33 -
      - Daily Paper - - All Products - - All Gender - - 7,738 - - 6,559.23 - - 16,479.81 -
      - Daily Paper, Radio - - All Products - - All Gender - - 6,891 - - 5,668.77 - - 14,169.42 -
      - Daily Paper, Radio, TV - - All Products - - All Gender - - 9,513 - - 8,055.22 - - 20,173.97 -
      - In-Store Coupon - - All Products - - All Gender - - 3,798 - - 3,263.11 - - 8,162.46 -
      - Drink - - All Gender - - 345 - - 282.44 - - 708.38 -
      - Food - - All Gender - - 2,737 - - 2,345.57 - - 5,889.34 -
      - Baked Goods - - All Gender - - 131 - - 114.11 - - 279.11 -
      - Baking Goods - - All Gender - - 308 - - 252.88 - - 632.01 -
      - Baking Goods - - All Gender - - 146 - - 103.30 - - 261.44 -
      - Jams and Jellies - - All Gender - - 162 - - 149.58 - - 370.57 -
      - Jam - - All Gender - - 55 - - 58.16 - - 141.19 -
      - Jelly - - All Gender - - 32 - - 23.96 - - 62.12 -
      - Peanut Butter - - All Gender - - 22 - - 19.54 - - 48.72 -
      - BBB Best - - All Gender - - 7 - - 6.72 - - 16.10 -
      - CDR - - All Gender - - 10 - - 9.81 - - 24.32 -
      - Landslide - - All Gender - -   - -   - -   -
      - Plato - - All Gender - - 3 - - 2.32 - - 6.32 -
      - Super - - All Gender - - 2 - - .69 - - 1.98 -
      - Preserves - - All Gender - - 53 - - 47.92 - - 118.54 -
      - Breakfast Foods - - All Gender - - 59 - - 49.22 - - 125.19 -
      - F - - 33 - - 22.88 - - 54.84 -
      - M - - 26 - - 26.34 - - 70.35 -
      - Canned Foods - - All Gender - - 245 - - 200.61 - - 506.67 -
      - Canned Products - - All Gender - - 15 - - 9.58 - - 26.17 -
      - Dairy - - All Gender - - 166 - - 153.42 - - 372.01 -
      - Deli - - All Gender - - 180 - - 163.58 - - 392.68 -
      - Eggs - - All Gender - - 56 - - 42.51 - - 108.90 -
      - Frozen Foods - - All Gender - - 374 - - 301.63 - - 773.52 -
      - Meat - - All Gender - - 31 - - 23.91 - - 70.35 -
      - Produce - - All Gender - - 563 - - 499.63 - - 1,257.05 -
      - Seafood - - All Gender - - 34 - - 30.06 - - 76.09 -
      - Snack Foods - - All Gender - - 439 - - 390.35 - - 989.13 -
      - Snacks - - All Gender - - 78 - - 63.77 - - 153.02 -
      - Starchy Foods - - All Gender - - 58 - - 50.30 - - 127.44 -
      - Non-Consumable - - All Gender - - 716 - - 635.10 - - 1,564.74 -
      - Carousel - - All Gender - - 17 - - 8.77 - - 24.18 -
      - Checkout - - All Gender - - 23 - - 15.20 - - 40.19 -
      - Health and Hygiene - - All Gender - - 251 - - 193.53 - - 477.21 -
      - Household - - All Gender - - 374 - - 375.66 - - 916.97 -
      - Periodicals - - All Gender - - 51 - - 41.94 - - 106.19 -
      - No Media - - All Products - - All Gender - - 195,448 - - 165,214.85 - - 414,026.92 -
      - Drink - - All Gender - - 17,896 - - 14,211.41 - - 35,681.85 -
      - Food - - All Gender - - 140,577 - - 119,469.36 - - 299,356.11 -
      - Baked Goods - - All Gender - - 5,753 - - 4,775.86 - - 11,972.46 -
      - Baking Goods - - All Gender - - 14,849 - - 11,226.15 - - 28,312.78 -
      - Baking Goods - - All Gender - - 5,979 - - 4,347.34 - - 11,002.73 -
      - Jams and Jellies - - All Gender - - 8,870 - - 6,878.81 - - 17,310.05 -
      - Jam - - All Gender - - 1,883 - - 1,554.13 - - 3,965.74 -
      - Jelly - - All Gender - - 1,936 - - 1,394.32 - - 3,504.71 -
      - Peanut Butter - - All Gender - - 1,984 - - 1,534.19 - - 3,828.01 -
      - BBB Best - - All Gender - - 406 - - 293.97 - - 735.29 -
      - CDR - - All Gender - - 411 - - 401.88 - - 998.12 -
      - Landslide - - All Gender - - 401 - - 195.51 - - 478.44 -
      - Plato - - All Gender - - 384 - - 331.26 - - 832.92 -
      - Super - - All Gender - - 382 - - 311.57 - - 783.24 -
      - Preserves - - All Gender - - 3,067 - - 2,396.16 - - 6,011.59 -
      - Breakfast Foods - - All Gender - - 2,418 - - 1,996.45 - - 5,016.10 -
      - Canned Foods - - All Gender - - 13,861 - - 11,647.47 - - 29,102.79 -
      - Canned Products - - All Gender - - 1,344 - - 960.82 - - 2,424.98 -
      - Dairy - - All Gender - - 9,510 - - 8,981.13 - - 22,454.02 -
      - Deli - - All Gender - - 8,695 - - 7,353.56 - - 18,410.26 -
      - Eggs - - All Gender - - 2,976 - - 2,640.47 - - 6,606.25 -
      - Frozen Foods - - All Gender - - 19,450 - - 16,127.24 - - 40,411.08 -
      - Meat - - All Gender - - 1,236 - - 1,068.07 - - 2,646.00 -
      - Produce - - All Gender - - 27,637 - - 24,036.36 - - 60,203.58 -
      - Seafood - - All Gender - - 1,292 - - 1,114.69 - - 2,774.43 -
      - Snack Foods - - All Gender - - 22,525 - - 19,800.82 - - 49,680.71 -
      - Snacks - - All Gender - - 5,100 - - 4,264.55 - - 10,690.26 -
      - Starchy Foods - - All Gender - - 3,931 - - 3,475.74 - - 8,650.41 -
      - Non-Consumable - - All Gender - - 36,975 - - 31,534.08 - - 78,988.96 -
      - Carousel - - All Gender - - 584 - - 419.65 - - 1,050.75 -
      - Checkout - - All Gender - - 1,305 - - 1,113.97 - - 2,768.66 -
      - Health and Hygiene - - All Gender - - 11,845 - - 9,413.25 - - 23,621.12 -
      - Household - - All Gender - - 20,091 - - 17,929.20 - - 44,881.13 -
      - Periodicals - - All Gender - - 3,150 - - 2,658.00 - - 6,667.30 -
      - Product Attachment - - All Products - - All Gender - - 7,544 - - 6,306.24 - - 15,898.25 -
      - Drink - - All Gender - - 713 - - 555.05 - - 1,403.65 -
      - Food - - All Gender - - 5,441 - - 4,571.71 - - 11,525.25 -
      - Baked Goods - - All Gender - - 213 - - 175.69 - - 445.60 -
      - Baking Goods - - All Gender - - 547 - - 410.31 - - 1,032.59 -
      - Baking Goods - - All Gender - - 258 - - 191.48 - - 470.58 -
      - Jams and Jellies - - All Gender - - 289 - - 218.83 - - 562.01 -
      - Jam - - All Gender - - 66 - - 48.03 - - 128.68 -
      - Jelly - - All Gender - - 45 - - 34.12 - - 90.62 -
      - Peanut Butter - - All Gender - - 63 - - 47.71 - - 122.31 -
      - BBB Best - - All Gender - - 15 - - 14.53 - - 38.46 -
      - CDR - - All Gender - - 13 - - 11.94 - - 30.57 -
      - Landslide - - All Gender - - 12 - - 5.32 - - 14.28 -
      - Plato - - All Gender - - 9 - - 7.16 - - 17.43 -
      - Super - - All Gender - - 14 - - 8.75 - - 21.57 -
      - Preserves - - All Gender - - 115 - - 88.98 - - 220.40 -
      - Breakfast Foods - - All Gender - - 103 - - 87.35 - - 220.75 -
      - Canned Foods - - All Gender - - 564 - - 463.28 - - 1,154.91 -
      - Canned Products - - All Gender - - 60 - - 51.61 - - 124.24 -
      - Dairy - - All Gender - - 355 - - 339.81 - - 849.78 -
      - Deli - - All Gender - - 324 - - 243.64 - - 618.23 -
      - Eggs - - All Gender - - 118 - - 97.43 - - 241.21 -
      - Frozen Foods - - All Gender - - 812 - - 665.48 - - 1,692.11 -
      - Meat - - All Gender - - 54 - - 51.36 - - 127.83 -
      - Produce - - All Gender - - 1,069 - - 909.24 - - 2,287.61 -
      - Seafood - - All Gender - - 45 - - 36.98 - - 100.61 -
      - Snack Foods - - All Gender - - 819 - - 726.73 - - 1,847.28 -
      - Snacks - - All Gender - - 209 - - 186.22 - - 450.03 -
      - Starchy Foods - - All Gender - - 149 - - 126.59 - - 332.47 -
      - Non-Consumable - - All Gender - - 1,390 - - 1,179.48 - - 2,969.35 -
      - Carousel - - All Gender - - 14 - - 7.99 - - 21.21 -
      - Checkout - - All Gender - - 48 - - 40.45 - - 100.61 -
      - Health and Hygiene - - All Gender - - 440 - - 356.54 - - 901.73 -
      - Household - - All Gender - - 777 - - 690.03 - - 1,737.96 -
      - Periodicals - - All Gender - - 111 - - 84.48 - - 207.84 -
      - Radio - - All Products - - All Gender - - 2,454 - - 2,087.51 - - 5,213.61 -
      - Drink - - All Gender - - 226 - - 182.85 - - 443.68 -
      - Food - - All Gender - - 1,733 - - 1,485.25 - - 3,727.36 -
      - Baked Goods - - All Gender - - 83 - - 76.51 - - 186.20 -
      - Baking Goods - - All Gender - - 157 - - 109.10 - - 274.90 -
      - Baking Goods - - All Gender - - 63 - - 45.02 - - 110.43 -
      - Jams and Jellies - - All Gender - - 94 - - 64.08 - - 164.47 -
      - Jam - - All Gender - - 15 - - 10.42 - - 26.94 -
      - Jelly - - All Gender - - 24 - - 14.54 - - 37.49 -
      - Peanut Butter - - All Gender - - 19 - - 16.85 - - 41.82 -
      - BBB Best - - All Gender - - 10 - - 10.58 - - 24.44 -
      - CDR - - All Gender - -   - -   - -   -
      - Landslide - - All Gender - -   - -   - -   -
      - Plato - - All Gender - - 4 - - 3.77 - - 9.80 -
      - Super - - All Gender - - 5 - - 2.50 - - 7.58 -
      - Preserves - - All Gender - - 36 - - 22.28 - - 58.22 -
      - Breakfast Foods - - All Gender - - 25 - - 18.78 - - 50.22 -
      - Canned Foods - - All Gender - - 158 - - 124.79 - - 307.55 -
      - Canned Products - - All Gender - - 22 - - 17.29 - - 43.42 -
      - Dairy - - All Gender - - 112 - - 92.12 - - 216.79 -
      - Deli - - All Gender - - 129 - - 119.14 - - 307.25 -
      - Eggs - - All Gender - - 25 - - 29.97 - - 71.15 -
      - Frozen Foods - - All Gender - - 253 - - 202.71 - - 507.45 -
      - Meat - - All Gender - - 12 - - 11.53 - - 32.85 -
      - Produce - - All Gender - - 336 - - 292.05 - - 738.20 -
      - Seafood - - All Gender - - 15 - - 13.28 - - 35.58 -
      - Snack Foods - - All Gender - - 290 - - 270.59 - - 674.73 -
      - Snacks - - All Gender - - 60 - - 55.67 - - 144.58 -
      - Starchy Foods - - All Gender - - 56 - - 51.72 - - 136.49 -
      - Non-Consumable - - All Gender - - 495 - - 419.41 - - 1,042.57 -
      - Carousel - - All Gender - - 15 - - 11.15 - - 26.85 -
      - Checkout - - All Gender - - 21 - - 17.00 - - 42.74 -
      - Health and Hygiene - - All Gender - - 145 - - 114.84 - - 289.80 -
      - Household - - All Gender - - 258 - - 233.31 - - 575.07 -
      - Periodicals - - All Gender - - 56 - - 43.12 - - 108.11 -
      - Street Handout - - All Products - - All Gender - - 5,753 - - 4,856.54 - - 12,192.90 -
      - Drink - - All Gender - - 512 - - 372.68 - - 943.42 -
      - Food - - All Gender - - 4,239 - - 3,650.32 - - 9,151.65 -
      - Baked Goods - - All Gender - - 160 - - 120.12 - - 301.62 -
      - Baking Goods - - All Gender - - 498 - - 373.67 - - 923.22 -
      - Baking Goods - - All Gender - - 200 - - 144.16 - - 357.82 -
      - Jams and Jellies - - All Gender - - 298 - - 229.51 - - 565.40 -
      - Jam - - All Gender - - 53 - - 44.30 - - 112.95 -
      - Jelly - - All Gender - - 92 - - 63.14 - - 155.59 -
      - Peanut Butter - - All Gender - - 51 - - 51.06 - - 118.90 -
      - BBB Best - - All Gender - - 11 - - 10.85 - - 25.72 -
      - CDR - - All Gender - - 8 - - 9.06 - - 19.73 -
      - Landslide - - All Gender - - 11 - - 6.90 - - 15.54 -
      - Plato - - All Gender - - 9 - - 8.47 - - 20.89 -
      - Super - - All Gender - - 12 - - 15.78 - - 37.02 -
      - Preserves - - All Gender - - 102 - - 71.02 - - 177.96 -
      - Breakfast Foods - - All Gender - - 81 - - 74.32 - - 192.90 -
      - Canned Foods - - All Gender - - 459 - - 413.21 - - 1,021.86 -
      - Canned Products - - All Gender - - 30 - - 19.43 - - 45.68 -
      - Dairy - - All Gender - - 301 - - 285.98 - - 718.61 -
      - Deli - - All Gender - - 305 - - 253.54 - - 638.30 -
      - Eggs - - All Gender - - 66 - - 59.15 - - 156.82 -
      - Frozen Foods - - All Gender - - 612 - - 520.12 - - 1,313.71 -
      - Meat - - All Gender - - 37 - - 29.82 - - 78.24 -
      - Produce - - All Gender - - 745 - - 662.39 - - 1,639.94 -
      - Seafood - - All Gender - - 37 - - 30.12 - - 72.77 -
      - Snack Foods - - All Gender - - 675 - - 600.23 - - 1,515.68 -
      - Snacks - - All Gender - - 144 - - 128.79 - - 321.16 -
      - Starchy Foods - - All Gender - - 89 - - 79.43 - - 211.14 -
      - Non-Consumable - - All Gender - - 1,002 - - 833.53 - - 2,097.83 -
      - Carousel - - All Gender - - 17 - - 13.53 - - 30.98 -
      - Checkout - - All Gender - - 45 - - 34.77 - - 85.38 -
      - Health and Hygiene - - All Gender - - 402 - - 318.03 - - 802.92 -
      - Household - - All Gender - - 501 - - 436.41 - - 1,105.38 -
      - Periodicals - - All Gender - - 37 - - 30.80 - - 73.17 -
      - Sunday Paper - - All Products - - All Gender - - 4,339 - - 3,673.86 - - 9,092.89 -
      - Drink - - All Gender - - 430 - - 345.53 - - 856.73 -
      - Food - - All Gender - - 3,106 - - 2,646.47 - - 6,559.46 -
      - Baked Goods - - All Gender - - 140 - - 110.79 - - 282.55 -
      - Baking Goods - - All Gender - - 338 - - 239.76 - - 603.86 -
      - Baking Goods - - All Gender - - 170 - - 118.05 - - 298.79 -
      - Jams and Jellies - - All Gender - - 168 - - 121.71 - - 305.07 -
      - Jam - - All Gender - - 24 - - 22.35 - - 54.83 -
      - Jelly - - All Gender - - 27 - - 18.20 - - 47.12 -
      - Peanut Butter - - All Gender - - 51 - - 37.67 - - 96.67 -
      - BBB Best - - All Gender - - 10 - - 6.08 - - 16.22 -
      - CDR - - All Gender - - 10 - - 10.47 - - 26.50 -
      - Landslide - - All Gender - - 15 - - 6.20 - - 16.31 -
      - Plato - - All Gender - - 16 - - 14.93 - - 37.64 -
      - Super - - All Gender - -   - -   - -   -
      - Preserves - - All Gender - - 66 - - 43.49 - - 106.45 -
      - Breakfast Foods - - All Gender - - 55 - - 49.80 - - 120.23 -
      - Canned Foods - - All Gender - - 283 - - 249.46 - - 605.11 -
      - Canned Products - - All Gender - - 34 - - 29.65 - - 72.18 -
      - Dairy - - All Gender - - 200 - - 201.94 - - 497.91 -
      - Deli - - All Gender - - 228 - - 188.37 - - 467.53 -
      - Eggs - - All Gender - - 54 - - 47.68 - - 118.44 -
      - Frozen Foods - - All Gender - - 425 - - 330.81 - - 839.15 -
      - Meat - - All Gender - - 18 - - 19.85 - - 52.20 -
      - Produce - - All Gender - - 603 - - 520.95 - - 1,274.70 -
      - Seafood - - All Gender - - 27 - - 26.82 - - 69.49 -
      - Snack Foods - - All Gender - - 469 - - 413.18 - - 1,027.98 -
      - Snacks - - All Gender - - 123 - - 108.50 - - 261.38 -
      - Starchy Foods - - All Gender - - 109 - - 108.91 - - 266.75 -
      - Non-Consumable - - All Gender - - 803 - - 681.86 - - 1,676.70 -
      - Carousel - - All Gender - - 7 - - 6.70 - - 14.68 -
      - Checkout - - All Gender - - 17 - - 13.09 - - 30.89 -
      - Health and Hygiene - - All Gender - - 278 - - 227.06 - - 565.99 -
      - Household - - All Gender - - 420 - - 371.58 - - 911.69 -
      - Periodicals - - All Gender - - 81 - - 63.43 - - 153.45 -
      - Sunday Paper, Radio - - All Products - - All Gender - - 5,945 - - 5,027.31 - - 12,551.96 -
      - Drink - - All Gender - - 591 - - 454.03 - - 1,129.94 -
      - Food - - All Gender - - 4,239 - - 3,612.38 - - 9,033.23 -
      - Baked Goods - - All Gender - - 152 - - 109.11 - - 274.39 -
      - Baking Goods - - All Gender - - 482 - - 367.13 - - 913.84 -
      - Baking Goods - - All Gender - - 206 - - 152.72 - - 381.59 -
      - Jams and Jellies - - All Gender - - 276 - - 214.41 - - 532.25 -
      - Jam - - All Gender - - 52 - - 52.39 - - 126.62 -
      - Jelly - - All Gender - - 74 - - 53.93 - - 135.03 -
      - Peanut Butter - - All Gender - - 64 - - 50.10 - - 126.71 -
      - BBB Best - - All Gender - - 14 - - 11.58 - - 27.40 -
      - CDR - - All Gender - - 17 - - 14.68 - - 41.25 -
      - Landslide - - All Gender - - 14 - - 6.62 - - 17.04 -
      - Plato - - All Gender - - 7 - - 6.91 - - 17.15 -
      - Super - - All Gender - - 12 - - 10.31 - - 23.87 -
      - Preserves - - All Gender - - 86 - - 57.99 - - 143.89 -
      - Breakfast Foods - - All Gender - - 80 - - 62.80 - - 154.04 -
      - Canned Foods - - All Gender - - 456 - - 361.79 - - 914.81 -
      - Canned Products - - All Gender - - 45 - - 39.72 - - 95.88 -
      - Dairy - - All Gender - - 283 - - 296.91 - - 722.75 -
      - Deli - - All Gender - - 252 - - 190.32 - - 479.59 -
      - Eggs - - All Gender - - 114 - - 104.65 - - 256.15 -
      - Frozen Foods - - All Gender - - 599 - - 490.33 - - 1,222.54 -
      - Meat - - All Gender - - 40 - - 31.66 - - 84.76 -
      - Produce - - All Gender - - 858 - - 752.62 - - 1,886.01 -
      - Seafood - - All Gender - - 27 - - 20.66 - - 50.39 -
      - Snack Foods - - All Gender - - 596 - - 555.70 - - 1,402.21 -
      - Snacks - - All Gender - - 147 - - 120.43 - - 304.18 -
      - Starchy Foods - - All Gender - - 108 - - 108.55 - - 271.69 -
      - Non-Consumable - - All Gender - - 1,115 - - 960.90 - - 2,388.79 -
      - Carousel - - All Gender - - 18 - - 10.99 - - 26.94 -
      - Checkout - - All Gender - - 26 - - 24.68 - - 62.14 -
      - Health and Hygiene - - All Gender - - 378 - - 309.37 - - 771.48 -
      - Household - - All Gender - - 585 - - 516.99 - - 1,276.16 -
      - Periodicals - - All Gender - - 108 - - 98.86 - - 252.07 -
      - Sunday Paper, Radio, TV - - All Products - - All Gender - - 2,726 - - 2,341.58 - - 5,819.33 -
      - Drink - - All Gender - - 225 - - 163.09 - - 403.51 -
      - Food - - All Gender - - 2,021 - - 1,762.18 - - 4,377.85 -
      - Baked Goods - - All Gender - - 67 - - 66.17 - - 163.29 -
      - Baking Goods - - All Gender - - 228 - - 182.98 - - 455.90 -
      - Baking Goods - - All Gender - - 90 - - 73.09 - - 176.63 -
      - Jams and Jellies - - All Gender - - 138 - - 109.90 - - 279.27 -
      - Jam - - All Gender - - 37 - - 31.30 - - 78.56 -
      - Jelly - - All Gender - - 27 - - 16.18 - - 39.92 -
      - Peanut Butter - - All Gender - - 30 - - 24.01 - - 64.19 -
      - BBB Best - - All Gender - - 11 - - 9.78 - - 23.86 -
      - CDR - - All Gender - -   - -   - -   -
      - Landslide - - All Gender - - 4 - - 2.39 - - 5.68 -
      - Plato - - All Gender - - 5 - - 3.85 - - 11.60 -
      - Super - - All Gender - - 10 - - 7.99 - - 23.05 -
      - Preserves - - All Gender - - 44 - - 38.41 - - 96.60 -
      - Breakfast Foods - - All Gender - - 38 - - 32.76 - - 89.85 -
      - Canned Foods - - All Gender - - 180 - - 138.77 - - 340.04 -
      - Canned Products - - All Gender - - 14 - - 12.00 - - 28.28 -
      - Dairy - - All Gender - - 121 - - 125.32 - - 305.43 -
      - Deli - - All Gender - - 131 - - 98.93 - - 245.42 -
      - Eggs - - All Gender - - 39 - - 39.57 - - 91.99 -
      - Frozen Foods - - All Gender - - 279 - - 207.59 - - 514.95 -
      - Meat - - All Gender - - 12 - - 11.77 - - 30.23 -
      - Produce - - All Gender - - 411 - - 382.14 - - 943.93 -
      - Seafood - - All Gender - - 31 - - 28.07 - - 69.82 -
      - Snack Foods - - All Gender - - 346 - - 318.26 - - 798.50 -
      - Snacks - - All Gender - - 75 - - 65.49 - - 174.02 -
      - Starchy Foods - - All Gender - - 49 - - 52.37 - - 126.20 -
      - Non-Consumable - - All Gender - - 480 - - 416.30 - - 1,037.97 -
      - Carousel - - All Gender - - 21 - - 11.63 - - 27.92 -
      - Checkout - - All Gender - - 10 - - 8.12 - - 19.80 -
      - Health and Hygiene - - All Gender - - 138 - - 110.35 - - 276.31 -
      - Household - - All Gender - - 262 - - 244.90 - - 608.52 -
      - Periodicals - - All Gender - - 49 - - 41.30 - - 105.42 -
      - TV - - All Products - - All Gender - - 3,607 - - 3,116.40 - - 7,786.21 -
      - Drink - - All Gender - - 332 - - 283.18 - - 721.07 -
      - Food - - All Gender - - 2,563 - - 2,238.13 - - 5,573.27 -
      - Baked Goods - - All Gender - - 114 - - 103.40 - - 262.97 -
      - Baking Goods - - All Gender - - 237 - - 185.55 - - 464.23 -
      - Baking Goods - - All Gender - - 95 - - 74.29 - - 190.59 -
      - Jams and Jellies - - All Gender - - 142 - - 111.25 - - 273.64 -
      - Jam - - All Gender - - 38 - - 32.28 - - 77.58 -
      - Jelly - - All Gender - - 35 - - 24.64 - - 63.38 -
      - Peanut Butter - - All Gender - - 31 - - 21.83 - - 56.80 -
      - BBB Best - - All Gender - -   - -   - -   -
      - CDR - - All Gender - - 11 - - 9.78 - - 27.19 -
      - Landslide - - All Gender - - 7 - - 2.61 - - 7.12 -
      - Plato - - All Gender - - 6 - - 4.95 - - 12.13 -
      - Super - - All Gender - - 7 - - 4.48 - - 10.36 -
      - Preserves - - All Gender - - 38 - - 32.51 - - 75.88 -
      - Breakfast Foods - - All Gender - - 36 - - 30.11 - - 79.89 -
      - Canned Foods - - All Gender - - 240 - - 200.00 - - 519.91 -
      - Canned Products - - All Gender - - 26 - - 15.00 - - 38.65 -
      - Dairy - - All Gender - - 179 - - 183.73 - - 458.87 -
      - Deli - - All Gender - - 155 - - 139.76 - - 342.51 -
      - Eggs - - All Gender - - 42 - - 32.74 - - 80.93 -
      - Frozen Foods - - All Gender - - 352 - - 300.42 - - 738.40 -
      - Meat - - All Gender - - 22 - - 19.76 - - 49.27 -
      - Produce - - All Gender - - 543 - - 456.53 - - 1,145.45 -
      - Seafood - - All Gender - - 34 - - 30.71 - - 75.47 -
      - Snack Foods - - All Gender - - 401 - - 377.01 - - 927.50 -
      - Snacks - - All Gender - - 99 - - 92.80 - - 220.54 -
      - Starchy Foods - - All Gender - - 83 - - 70.61 - - 168.68 -
      - Non-Consumable - - All Gender - - 712 - - 595.08 - - 1,491.87 -
      - Carousel - - All Gender - - 4 - - 3.13 - - 9.20 -
      - Checkout - - All Gender - - 34 - - 34.12 - - 86.21 -
      - Health and Hygiene - - All Gender - - 249 - - 196.08 - - 486.46 -
      - Household - - All Gender - - 361 - - 316.09 - - 795.40 -
      - Periodicals - - All Gender - - 64 - - 45.67 - - 114.60 -
      +   + + Measures +
      + Promotion Media + + Product + + Gender + + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + All Products + + All Gender + + 266,773 + + 225,627.23 + + 565,238.13 +
      + Drink + + All Gender + + 24,597 + + 19,477.23 + + 48,836.21 +
      + Food + + All Gender + + 191,940 + + 163,270.72 + + 409,035.59 +
      + Baked Goods + + All Gender + + 7,870 + + 6,564.09 + + 16,455.43 +
      + Baking Goods + + All Gender + + 20,245 + + 15,370.61 + + 38,670.41 +
      + Baking Goods + + All Gender + + 8,357 + + 6,123.32 + + 15,446.69 +
      + F + + 4,005 + + 2,907.70 + + 7,313.61 +
      + M + + 4,352 + + 3,215.62 + + 8,133.08 +
      + Jams and Jellies + + All Gender + + 11,888 + + 9,247.29 + + 23,223.72 +
      + Jam + + All Gender + + 2,556 + + 2,132.27 + + 5,401.81 +
      + Jelly + + All Gender + + 2,565 + + 1,830.04 + + 4,609.61 +
      + F + + 1,309 + + 956.94 + + 2,414.94 +
      + M + + 1,256 + + 873.10 + + 2,194.67 +
      + Peanut Butter + + All Gender + + 2,667 + + 2,097.37 + + 5,231.08 +
      + BBB Best + + All Gender + + 556 + + 424.38 + + 1,055.72 +
      + F + + 271 + + 201.08 + + 500.39 +
      + M + + 285 + + 223.30 + + 555.33 +
      + BBB Best Chunky Peanut Butter + + All Gender + + 188 + + 147.32 + + 370.36 +
      + F + + 107 + + 85.81 + + 210.79 +
      + M + + 81 + + 61.50 + + 159.57 +
      + BBB Best Creamy Peanut Butter + + All Gender + + 201 + + 87.86 + + 221.10 +
      + F + + 99 + + 43.35 + + 108.90 +
      + M + + 102 + + 44.51 + + 112.20 +
      + BBB Best Extra Chunky Peanut Butter + + All Gender + + 167 + + 189.21 + + 464.26 +
      + F + + 65 + + 71.92 + + 180.70 +
      + M + + 102 + + 117.29 + + 283.56 +
      + CDR + + All Gender + + 545 + + 538.88 + + 1,326.30 +
      + Landslide + + All Gender + + 531 + + 256.16 + + 635.29 +
      + Plato + + All Gender + + 520 + + 447.73 + + 1,132.16 +
      + Super + + All Gender + + 515 + + 430.21 + + 1,081.61 +
      + Preserves + + All Gender + + 4,100 + + 3,187.61 + + 7,981.22 +
      + F + + 1,946 + + 1,472.42 + + 3,717.80 +
      + M + + 2,154 + + 1,715.19 + + 4,263.42 +
      + Breakfast Foods + + All Gender + + 3,317 + + 2,756.80 + + 6,941.46 +
      + Canned Foods + + All Gender + + 19,026 + + 15,894.53 + + 39,774.34 +
      + Canned Anchovies + + All Gender + + 900 + + 913.88 + + 2,296.38 +
      + Canned Clams + + All Gender + + 882 + + 759.80 + + 1,912.68 +
      + Clams + + All Gender + + 882 + + 759.80 + + 1,912.68 +
      + Better + + All Gender + + 189 + + 151.14 + + 398.79 +
      + Blue Label + + All Gender + + 165 + + 112.82 + + 278.85 +
      + Bravo + + All Gender + + 184 + + 280.70 + + 708.40 +
      + Just Right + + All Gender + + 177 + + 161.96 + + 394.71 +
      + Pleasant + + All Gender + + 167 + + 53.17 + + 131.93 +
      + Canned Oysters + + All Gender + + 708 + + 571.50 + + 1,442.77 +
      + Canned Sardines + + All Gender + + 819 + + 537.59 + + 1,357.80 +
      + Canned Shrimp + + All Gender + + 804 + + 858.39 + + 2,146.49 +
      + Canned Soup + + All Gender + + 8,006 + + 6,408.29 + + 15,966.10 +
      + Canned Tuna + + All Gender + + 1,710 + + 1,288.52 + + 3,210.76 +
      + Vegetables + + All Gender + + 5,197 + + 4,556.57 + + 11,441.36 +
      + Canned Products + + All Gender + + 1,812 + + 1,317.13 + + 3,314.52 +
      + Dairy + + All Gender + + 12,885 + + 12,228.85 + + 30,508.85 +
      + Deli + + All Gender + + 12,037 + + 10,108.87 + + 25,318.93 +
      + Meat + + All Gender + + 9,433 + + 8,215.81 + + 20,616.29 +
      + Bologna + + All Gender + + 2,588 + + 2,340.24 + + 5,859.95 +
      + Deli Meats + + All Gender + + 3,339 + + 2,851.18 + + 7,191.24 +
      + F + + 1,653 + + 1,414.49 + + 3,579.34 +
      + M + + 1,686 + + 1,436.69 + + 3,611.90 +
      + Fresh Chicken + + All Gender + + 878 + + 842.85 + + 2,091.52 +
      + Hot Dogs + + All Gender + + 2,628 + + 2,181.55 + + 5,473.58 +
      + Side Dishes + + All Gender + + 2,604 + + 1,893.06 + + 4,702.64 +
      + Eggs + + All Gender + + 4,132 + + 3,684.90 + + 9,200.76 +
      + Frozen Foods + + All Gender + + 26,655 + + 22,030.66 + + 55,207.50 +
      + Meat + + All Gender + + 1,714 + + 1,465.42 + + 3,669.89 +
      + Produce + + All Gender + + 37,792 + + 32,831.33 + + 82,248.42 +
      + Seafood + + All Gender + + 1,764 + + 1,520.70 + + 3,809.14 +
      + Snack Foods + + All Gender + + 30,545 + + 26,963.34 + + 67,609.82 +
      + Snacks + + All Gender + + 6,884 + + 5,827.58 + + 14,550.05 +
      + Starchy Foods + + All Gender + + 5,262 + + 4,705.91 + + 11,756.07 +
      + Non-Consumable + + All Gender + + 50,236 + + 42,879.28 + + 107,366.33 +
      + Carousel + + All Gender + + 841 + + 595.97 + + 1,500.11 +
      + Checkout + + All Gender + + 1,779 + + 1,525.04 + + 3,767.71 +
      + Health and Hygiene + + All Gender + + 16,284 + + 12,972.99 + + 32,571.86 +
      + Household + + All Gender + + 27,038 + + 24,170.73 + + 60,469.89 +
      + Periodicals + + All Gender + + 4,294 + + 3,614.55 + + 9,056.76 +
      + Bulk Mail + + All Products + + All Gender + + 4,320 + + 3,740.95 + + 9,349.07 +
      + Cash Register Handout + + All Products + + All Gender + + 6,697 + + 5,715.67 + + 14,321.33 +
      + Daily Paper + + All Products + + All Gender + + 7,738 + + 6,559.23 + + 16,479.81 +
      + Daily Paper, Radio + + All Products + + All Gender + + 6,891 + + 5,668.77 + + 14,169.42 +
      + Daily Paper, Radio, TV + + All Products + + All Gender + + 9,513 + + 8,055.22 + + 20,173.97 +
      + In-Store Coupon + + All Products + + All Gender + + 3,798 + + 3,263.11 + + 8,162.46 +
      + Drink + + All Gender + + 345 + + 282.44 + + 708.38 +
      + Food + + All Gender + + 2,737 + + 2,345.57 + + 5,889.34 +
      + Baked Goods + + All Gender + + 131 + + 114.11 + + 279.11 +
      + Baking Goods + + All Gender + + 308 + + 252.88 + + 632.01 +
      + Baking Goods + + All Gender + + 146 + + 103.30 + + 261.44 +
      + Jams and Jellies + + All Gender + + 162 + + 149.58 + + 370.57 +
      + Jam + + All Gender + + 55 + + 58.16 + + 141.19 +
      + Jelly + + All Gender + + 32 + + 23.96 + + 62.12 +
      + Peanut Butter + + All Gender + + 22 + + 19.54 + + 48.72 +
      + BBB Best + + All Gender + + 7 + + 6.72 + + 16.10 +
      + CDR + + All Gender + + 10 + + 9.81 + + 24.32 +
      + Landslide + + All Gender + +   + +   + +   +
      + Plato + + All Gender + + 3 + + 2.32 + + 6.32 +
      + Super + + All Gender + + 2 + + .69 + + 1.98 +
      + Preserves + + All Gender + + 53 + + 47.92 + + 118.54 +
      + Breakfast Foods + + All Gender + + 59 + + 49.22 + + 125.19 +
      + F + + 33 + + 22.88 + + 54.84 +
      + M + + 26 + + 26.34 + + 70.35 +
      + Canned Foods + + All Gender + + 245 + + 200.61 + + 506.67 +
      + Canned Products + + All Gender + + 15 + + 9.58 + + 26.17 +
      + Dairy + + All Gender + + 166 + + 153.42 + + 372.01 +
      + Deli + + All Gender + + 180 + + 163.58 + + 392.68 +
      + Eggs + + All Gender + + 56 + + 42.51 + + 108.90 +
      + Frozen Foods + + All Gender + + 374 + + 301.63 + + 773.52 +
      + Meat + + All Gender + + 31 + + 23.91 + + 70.35 +
      + Produce + + All Gender + + 563 + + 499.63 + + 1,257.05 +
      + Seafood + + All Gender + + 34 + + 30.06 + + 76.09 +
      + Snack Foods + + All Gender + + 439 + + 390.35 + + 989.13 +
      + Snacks + + All Gender + + 78 + + 63.77 + + 153.02 +
      + Starchy Foods + + All Gender + + 58 + + 50.30 + + 127.44 +
      + Non-Consumable + + All Gender + + 716 + + 635.10 + + 1,564.74 +
      + Carousel + + All Gender + + 17 + + 8.77 + + 24.18 +
      + Checkout + + All Gender + + 23 + + 15.20 + + 40.19 +
      + Health and Hygiene + + All Gender + + 251 + + 193.53 + + 477.21 +
      + Household + + All Gender + + 374 + + 375.66 + + 916.97 +
      + Periodicals + + All Gender + + 51 + + 41.94 + + 106.19 +
      + No Media + + All Products + + All Gender + + 195,448 + + 165,214.85 + + 414,026.92 +
      + Drink + + All Gender + + 17,896 + + 14,211.41 + + 35,681.85 +
      + Food + + All Gender + + 140,577 + + 119,469.36 + + 299,356.11 +
      + Baked Goods + + All Gender + + 5,753 + + 4,775.86 + + 11,972.46 +
      + Baking Goods + + All Gender + + 14,849 + + 11,226.15 + + 28,312.78 +
      + Baking Goods + + All Gender + + 5,979 + + 4,347.34 + + 11,002.73 +
      + Jams and Jellies + + All Gender + + 8,870 + + 6,878.81 + + 17,310.05 +
      + Jam + + All Gender + + 1,883 + + 1,554.13 + + 3,965.74 +
      + Jelly + + All Gender + + 1,936 + + 1,394.32 + + 3,504.71 +
      + Peanut Butter + + All Gender + + 1,984 + + 1,534.19 + + 3,828.01 +
      + BBB Best + + All Gender + + 406 + + 293.97 + + 735.29 +
      + CDR + + All Gender + + 411 + + 401.88 + + 998.12 +
      + Landslide + + All Gender + + 401 + + 195.51 + + 478.44 +
      + Plato + + All Gender + + 384 + + 331.26 + + 832.92 +
      + Super + + All Gender + + 382 + + 311.57 + + 783.24 +
      + Preserves + + All Gender + + 3,067 + + 2,396.16 + + 6,011.59 +
      + Breakfast Foods + + All Gender + + 2,418 + + 1,996.45 + + 5,016.10 +
      + Canned Foods + + All Gender + + 13,861 + + 11,647.47 + + 29,102.79 +
      + Canned Products + + All Gender + + 1,344 + + 960.82 + + 2,424.98 +
      + Dairy + + All Gender + + 9,510 + + 8,981.13 + + 22,454.02 +
      + Deli + + All Gender + + 8,695 + + 7,353.56 + + 18,410.26 +
      + Eggs + + All Gender + + 2,976 + + 2,640.47 + + 6,606.25 +
      + Frozen Foods + + All Gender + + 19,450 + + 16,127.24 + + 40,411.08 +
      + Meat + + All Gender + + 1,236 + + 1,068.07 + + 2,646.00 +
      + Produce + + All Gender + + 27,637 + + 24,036.36 + + 60,203.58 +
      + Seafood + + All Gender + + 1,292 + + 1,114.69 + + 2,774.43 +
      + Snack Foods + + All Gender + + 22,525 + + 19,800.82 + + 49,680.71 +
      + Snacks + + All Gender + + 5,100 + + 4,264.55 + + 10,690.26 +
      + Starchy Foods + + All Gender + + 3,931 + + 3,475.74 + + 8,650.41 +
      + Non-Consumable + + All Gender + + 36,975 + + 31,534.08 + + 78,988.96 +
      + Carousel + + All Gender + + 584 + + 419.65 + + 1,050.75 +
      + Checkout + + All Gender + + 1,305 + + 1,113.97 + + 2,768.66 +
      + Health and Hygiene + + All Gender + + 11,845 + + 9,413.25 + + 23,621.12 +
      + Household + + All Gender + + 20,091 + + 17,929.20 + + 44,881.13 +
      + Periodicals + + All Gender + + 3,150 + + 2,658.00 + + 6,667.30 +
      + Product Attachment + + All Products + + All Gender + + 7,544 + + 6,306.24 + + 15,898.25 +
      + Drink + + All Gender + + 713 + + 555.05 + + 1,403.65 +
      + Food + + All Gender + + 5,441 + + 4,571.71 + + 11,525.25 +
      + Baked Goods + + All Gender + + 213 + + 175.69 + + 445.60 +
      + Baking Goods + + All Gender + + 547 + + 410.31 + + 1,032.59 +
      + Baking Goods + + All Gender + + 258 + + 191.48 + + 470.58 +
      + Jams and Jellies + + All Gender + + 289 + + 218.83 + + 562.01 +
      + Jam + + All Gender + + 66 + + 48.03 + + 128.68 +
      + Jelly + + All Gender + + 45 + + 34.12 + + 90.62 +
      + Peanut Butter + + All Gender + + 63 + + 47.71 + + 122.31 +
      + BBB Best + + All Gender + + 15 + + 14.53 + + 38.46 +
      + CDR + + All Gender + + 13 + + 11.94 + + 30.57 +
      + Landslide + + All Gender + + 12 + + 5.32 + + 14.28 +
      + Plato + + All Gender + + 9 + + 7.16 + + 17.43 +
      + Super + + All Gender + + 14 + + 8.75 + + 21.57 +
      + Preserves + + All Gender + + 115 + + 88.98 + + 220.40 +
      + Breakfast Foods + + All Gender + + 103 + + 87.35 + + 220.75 +
      + Canned Foods + + All Gender + + 564 + + 463.28 + + 1,154.91 +
      + Canned Products + + All Gender + + 60 + + 51.61 + + 124.24 +
      + Dairy + + All Gender + + 355 + + 339.81 + + 849.78 +
      + Deli + + All Gender + + 324 + + 243.64 + + 618.23 +
      + Eggs + + All Gender + + 118 + + 97.43 + + 241.21 +
      + Frozen Foods + + All Gender + + 812 + + 665.48 + + 1,692.11 +
      + Meat + + All Gender + + 54 + + 51.36 + + 127.83 +
      + Produce + + All Gender + + 1,069 + + 909.24 + + 2,287.61 +
      + Seafood + + All Gender + + 45 + + 36.98 + + 100.61 +
      + Snack Foods + + All Gender + + 819 + + 726.73 + + 1,847.28 +
      + Snacks + + All Gender + + 209 + + 186.22 + + 450.03 +
      + Starchy Foods + + All Gender + + 149 + + 126.59 + + 332.47 +
      + Non-Consumable + + All Gender + + 1,390 + + 1,179.48 + + 2,969.35 +
      + Carousel + + All Gender + + 14 + + 7.99 + + 21.21 +
      + Checkout + + All Gender + + 48 + + 40.45 + + 100.61 +
      + Health and Hygiene + + All Gender + + 440 + + 356.54 + + 901.73 +
      + Household + + All Gender + + 777 + + 690.03 + + 1,737.96 +
      + Periodicals + + All Gender + + 111 + + 84.48 + + 207.84 +
      + Radio + + All Products + + All Gender + + 2,454 + + 2,087.51 + + 5,213.61 +
      + Drink + + All Gender + + 226 + + 182.85 + + 443.68 +
      + Food + + All Gender + + 1,733 + + 1,485.25 + + 3,727.36 +
      + Baked Goods + + All Gender + + 83 + + 76.51 + + 186.20 +
      + Baking Goods + + All Gender + + 157 + + 109.10 + + 274.90 +
      + Baking Goods + + All Gender + + 63 + + 45.02 + + 110.43 +
      + Jams and Jellies + + All Gender + + 94 + + 64.08 + + 164.47 +
      + Jam + + All Gender + + 15 + + 10.42 + + 26.94 +
      + Jelly + + All Gender + + 24 + + 14.54 + + 37.49 +
      + Peanut Butter + + All Gender + + 19 + + 16.85 + + 41.82 +
      + BBB Best + + All Gender + + 10 + + 10.58 + + 24.44 +
      + CDR + + All Gender + +   + +   + +   +
      + Landslide + + All Gender + +   + +   + +   +
      + Plato + + All Gender + + 4 + + 3.77 + + 9.80 +
      + Super + + All Gender + + 5 + + 2.50 + + 7.58 +
      + Preserves + + All Gender + + 36 + + 22.28 + + 58.22 +
      + Breakfast Foods + + All Gender + + 25 + + 18.78 + + 50.22 +
      + Canned Foods + + All Gender + + 158 + + 124.79 + + 307.55 +
      + Canned Products + + All Gender + + 22 + + 17.29 + + 43.42 +
      + Dairy + + All Gender + + 112 + + 92.12 + + 216.79 +
      + Deli + + All Gender + + 129 + + 119.14 + + 307.25 +
      + Eggs + + All Gender + + 25 + + 29.97 + + 71.15 +
      + Frozen Foods + + All Gender + + 253 + + 202.71 + + 507.45 +
      + Meat + + All Gender + + 12 + + 11.53 + + 32.85 +
      + Produce + + All Gender + + 336 + + 292.05 + + 738.20 +
      + Seafood + + All Gender + + 15 + + 13.28 + + 35.58 +
      + Snack Foods + + All Gender + + 290 + + 270.59 + + 674.73 +
      + Snacks + + All Gender + + 60 + + 55.67 + + 144.58 +
      + Starchy Foods + + All Gender + + 56 + + 51.72 + + 136.49 +
      + Non-Consumable + + All Gender + + 495 + + 419.41 + + 1,042.57 +
      + Carousel + + All Gender + + 15 + + 11.15 + + 26.85 +
      + Checkout + + All Gender + + 21 + + 17.00 + + 42.74 +
      + Health and Hygiene + + All Gender + + 145 + + 114.84 + + 289.80 +
      + Household + + All Gender + + 258 + + 233.31 + + 575.07 +
      + Periodicals + + All Gender + + 56 + + 43.12 + + 108.11 +
      + Street Handout + + All Products + + All Gender + + 5,753 + + 4,856.54 + + 12,192.90 +
      + Drink + + All Gender + + 512 + + 372.68 + + 943.42 +
      + Food + + All Gender + + 4,239 + + 3,650.32 + + 9,151.65 +
      + Baked Goods + + All Gender + + 160 + + 120.12 + + 301.62 +
      + Baking Goods + + All Gender + + 498 + + 373.67 + + 923.22 +
      + Baking Goods + + All Gender + + 200 + + 144.16 + + 357.82 +
      + Jams and Jellies + + All Gender + + 298 + + 229.51 + + 565.40 +
      + Jam + + All Gender + + 53 + + 44.30 + + 112.95 +
      + Jelly + + All Gender + + 92 + + 63.14 + + 155.59 +
      + Peanut Butter + + All Gender + + 51 + + 51.06 + + 118.90 +
      + BBB Best + + All Gender + + 11 + + 10.85 + + 25.72 +
      + CDR + + All Gender + + 8 + + 9.06 + + 19.73 +
      + Landslide + + All Gender + + 11 + + 6.90 + + 15.54 +
      + Plato + + All Gender + + 9 + + 8.47 + + 20.89 +
      + Super + + All Gender + + 12 + + 15.78 + + 37.02 +
      + Preserves + + All Gender + + 102 + + 71.02 + + 177.96 +
      + Breakfast Foods + + All Gender + + 81 + + 74.32 + + 192.90 +
      + Canned Foods + + All Gender + + 459 + + 413.21 + + 1,021.86 +
      + Canned Products + + All Gender + + 30 + + 19.43 + + 45.68 +
      + Dairy + + All Gender + + 301 + + 285.98 + + 718.61 +
      + Deli + + All Gender + + 305 + + 253.54 + + 638.30 +
      + Eggs + + All Gender + + 66 + + 59.15 + + 156.82 +
      + Frozen Foods + + All Gender + + 612 + + 520.12 + + 1,313.71 +
      + Meat + + All Gender + + 37 + + 29.82 + + 78.24 +
      + Produce + + All Gender + + 745 + + 662.39 + + 1,639.94 +
      + Seafood + + All Gender + + 37 + + 30.12 + + 72.77 +
      + Snack Foods + + All Gender + + 675 + + 600.23 + + 1,515.68 +
      + Snacks + + All Gender + + 144 + + 128.79 + + 321.16 +
      + Starchy Foods + + All Gender + + 89 + + 79.43 + + 211.14 +
      + Non-Consumable + + All Gender + + 1,002 + + 833.53 + + 2,097.83 +
      + Carousel + + All Gender + + 17 + + 13.53 + + 30.98 +
      + Checkout + + All Gender + + 45 + + 34.77 + + 85.38 +
      + Health and Hygiene + + All Gender + + 402 + + 318.03 + + 802.92 +
      + Household + + All Gender + + 501 + + 436.41 + + 1,105.38 +
      + Periodicals + + All Gender + + 37 + + 30.80 + + 73.17 +
      + Sunday Paper + + All Products + + All Gender + + 4,339 + + 3,673.86 + + 9,092.89 +
      + Drink + + All Gender + + 430 + + 345.53 + + 856.73 +
      + Food + + All Gender + + 3,106 + + 2,646.47 + + 6,559.46 +
      + Baked Goods + + All Gender + + 140 + + 110.79 + + 282.55 +
      + Baking Goods + + All Gender + + 338 + + 239.76 + + 603.86 +
      + Baking Goods + + All Gender + + 170 + + 118.05 + + 298.79 +
      + Jams and Jellies + + All Gender + + 168 + + 121.71 + + 305.07 +
      + Jam + + All Gender + + 24 + + 22.35 + + 54.83 +
      + Jelly + + All Gender + + 27 + + 18.20 + + 47.12 +
      + Peanut Butter + + All Gender + + 51 + + 37.67 + + 96.67 +
      + BBB Best + + All Gender + + 10 + + 6.08 + + 16.22 +
      + CDR + + All Gender + + 10 + + 10.47 + + 26.50 +
      + Landslide + + All Gender + + 15 + + 6.20 + + 16.31 +
      + Plato + + All Gender + + 16 + + 14.93 + + 37.64 +
      + Super + + All Gender + +   + +   + +   +
      + Preserves + + All Gender + + 66 + + 43.49 + + 106.45 +
      + Breakfast Foods + + All Gender + + 55 + + 49.80 + + 120.23 +
      + Canned Foods + + All Gender + + 283 + + 249.46 + + 605.11 +
      + Canned Products + + All Gender + + 34 + + 29.65 + + 72.18 +
      + Dairy + + All Gender + + 200 + + 201.94 + + 497.91 +
      + Deli + + All Gender + + 228 + + 188.37 + + 467.53 +
      + Eggs + + All Gender + + 54 + + 47.68 + + 118.44 +
      + Frozen Foods + + All Gender + + 425 + + 330.81 + + 839.15 +
      + Meat + + All Gender + + 18 + + 19.85 + + 52.20 +
      + Produce + + All Gender + + 603 + + 520.95 + + 1,274.70 +
      + Seafood + + All Gender + + 27 + + 26.82 + + 69.49 +
      + Snack Foods + + All Gender + + 469 + + 413.18 + + 1,027.98 +
      + Snacks + + All Gender + + 123 + + 108.50 + + 261.38 +
      + Starchy Foods + + All Gender + + 109 + + 108.91 + + 266.75 +
      + Non-Consumable + + All Gender + + 803 + + 681.86 + + 1,676.70 +
      + Carousel + + All Gender + + 7 + + 6.70 + + 14.68 +
      + Checkout + + All Gender + + 17 + + 13.09 + + 30.89 +
      + Health and Hygiene + + All Gender + + 278 + + 227.06 + + 565.99 +
      + Household + + All Gender + + 420 + + 371.58 + + 911.69 +
      + Periodicals + + All Gender + + 81 + + 63.43 + + 153.45 +
      + Sunday Paper, Radio + + All Products + + All Gender + + 5,945 + + 5,027.31 + + 12,551.96 +
      + Drink + + All Gender + + 591 + + 454.03 + + 1,129.94 +
      + Food + + All Gender + + 4,239 + + 3,612.38 + + 9,033.23 +
      + Baked Goods + + All Gender + + 152 + + 109.11 + + 274.39 +
      + Baking Goods + + All Gender + + 482 + + 367.13 + + 913.84 +
      + Baking Goods + + All Gender + + 206 + + 152.72 + + 381.59 +
      + Jams and Jellies + + All Gender + + 276 + + 214.41 + + 532.25 +
      + Jam + + All Gender + + 52 + + 52.39 + + 126.62 +
      + Jelly + + All Gender + + 74 + + 53.93 + + 135.03 +
      + Peanut Butter + + All Gender + + 64 + + 50.10 + + 126.71 +
      + BBB Best + + All Gender + + 14 + + 11.58 + + 27.40 +
      + CDR + + All Gender + + 17 + + 14.68 + + 41.25 +
      + Landslide + + All Gender + + 14 + + 6.62 + + 17.04 +
      + Plato + + All Gender + + 7 + + 6.91 + + 17.15 +
      + Super + + All Gender + + 12 + + 10.31 + + 23.87 +
      + Preserves + + All Gender + + 86 + + 57.99 + + 143.89 +
      + Breakfast Foods + + All Gender + + 80 + + 62.80 + + 154.04 +
      + Canned Foods + + All Gender + + 456 + + 361.79 + + 914.81 +
      + Canned Products + + All Gender + + 45 + + 39.72 + + 95.88 +
      + Dairy + + All Gender + + 283 + + 296.91 + + 722.75 +
      + Deli + + All Gender + + 252 + + 190.32 + + 479.59 +
      + Eggs + + All Gender + + 114 + + 104.65 + + 256.15 +
      + Frozen Foods + + All Gender + + 599 + + 490.33 + + 1,222.54 +
      + Meat + + All Gender + + 40 + + 31.66 + + 84.76 +
      + Produce + + All Gender + + 858 + + 752.62 + + 1,886.01 +
      + Seafood + + All Gender + + 27 + + 20.66 + + 50.39 +
      + Snack Foods + + All Gender + + 596 + + 555.70 + + 1,402.21 +
      + Snacks + + All Gender + + 147 + + 120.43 + + 304.18 +
      + Starchy Foods + + All Gender + + 108 + + 108.55 + + 271.69 +
      + Non-Consumable + + All Gender + + 1,115 + + 960.90 + + 2,388.79 +
      + Carousel + + All Gender + + 18 + + 10.99 + + 26.94 +
      + Checkout + + All Gender + + 26 + + 24.68 + + 62.14 +
      + Health and Hygiene + + All Gender + + 378 + + 309.37 + + 771.48 +
      + Household + + All Gender + + 585 + + 516.99 + + 1,276.16 +
      + Periodicals + + All Gender + + 108 + + 98.86 + + 252.07 +
      + Sunday Paper, Radio, TV + + All Products + + All Gender + + 2,726 + + 2,341.58 + + 5,819.33 +
      + Drink + + All Gender + + 225 + + 163.09 + + 403.51 +
      + Food + + All Gender + + 2,021 + + 1,762.18 + + 4,377.85 +
      + Baked Goods + + All Gender + + 67 + + 66.17 + + 163.29 +
      + Baking Goods + + All Gender + + 228 + + 182.98 + + 455.90 +
      + Baking Goods + + All Gender + + 90 + + 73.09 + + 176.63 +
      + Jams and Jellies + + All Gender + + 138 + + 109.90 + + 279.27 +
      + Jam + + All Gender + + 37 + + 31.30 + + 78.56 +
      + Jelly + + All Gender + + 27 + + 16.18 + + 39.92 +
      + Peanut Butter + + All Gender + + 30 + + 24.01 + + 64.19 +
      + BBB Best + + All Gender + + 11 + + 9.78 + + 23.86 +
      + CDR + + All Gender + +   + +   + +   +
      + Landslide + + All Gender + + 4 + + 2.39 + + 5.68 +
      + Plato + + All Gender + + 5 + + 3.85 + + 11.60 +
      + Super + + All Gender + + 10 + + 7.99 + + 23.05 +
      + Preserves + + All Gender + + 44 + + 38.41 + + 96.60 +
      + Breakfast Foods + + All Gender + + 38 + + 32.76 + + 89.85 +
      + Canned Foods + + All Gender + + 180 + + 138.77 + + 340.04 +
      + Canned Products + + All Gender + + 14 + + 12.00 + + 28.28 +
      + Dairy + + All Gender + + 121 + + 125.32 + + 305.43 +
      + Deli + + All Gender + + 131 + + 98.93 + + 245.42 +
      + Eggs + + All Gender + + 39 + + 39.57 + + 91.99 +
      + Frozen Foods + + All Gender + + 279 + + 207.59 + + 514.95 +
      + Meat + + All Gender + + 12 + + 11.77 + + 30.23 +
      + Produce + + All Gender + + 411 + + 382.14 + + 943.93 +
      + Seafood + + All Gender + + 31 + + 28.07 + + 69.82 +
      + Snack Foods + + All Gender + + 346 + + 318.26 + + 798.50 +
      + Snacks + + All Gender + + 75 + + 65.49 + + 174.02 +
      + Starchy Foods + + All Gender + + 49 + + 52.37 + + 126.20 +
      + Non-Consumable + + All Gender + + 480 + + 416.30 + + 1,037.97 +
      + Carousel + + All Gender + + 21 + + 11.63 + + 27.92 +
      + Checkout + + All Gender + + 10 + + 8.12 + + 19.80 +
      + Health and Hygiene + + All Gender + + 138 + + 110.35 + + 276.31 +
      + Household + + All Gender + + 262 + + 244.90 + + 608.52 +
      + Periodicals + + All Gender + + 49 + + 41.30 + + 105.42 +
      + TV + + All Products + + All Gender + + 3,607 + + 3,116.40 + + 7,786.21 +
      + Drink + + All Gender + + 332 + + 283.18 + + 721.07 +
      + Food + + All Gender + + 2,563 + + 2,238.13 + + 5,573.27 +
      + Baked Goods + + All Gender + + 114 + + 103.40 + + 262.97 +
      + Baking Goods + + All Gender + + 237 + + 185.55 + + 464.23 +
      + Baking Goods + + All Gender + + 95 + + 74.29 + + 190.59 +
      + Jams and Jellies + + All Gender + + 142 + + 111.25 + + 273.64 +
      + Jam + + All Gender + + 38 + + 32.28 + + 77.58 +
      + Jelly + + All Gender + + 35 + + 24.64 + + 63.38 +
      + Peanut Butter + + All Gender + + 31 + + 21.83 + + 56.80 +
      + BBB Best + + All Gender + +   + +   + +   +
      + CDR + + All Gender + + 11 + + 9.78 + + 27.19 +
      + Landslide + + All Gender + + 7 + + 2.61 + + 7.12 +
      + Plato + + All Gender + + 6 + + 4.95 + + 12.13 +
      + Super + + All Gender + + 7 + + 4.48 + + 10.36 +
      + Preserves + + All Gender + + 38 + + 32.51 + + 75.88 +
      + Breakfast Foods + + All Gender + + 36 + + 30.11 + + 79.89 +
      + Canned Foods + + All Gender + + 240 + + 200.00 + + 519.91 +
      + Canned Products + + All Gender + + 26 + + 15.00 + + 38.65 +
      + Dairy + + All Gender + + 179 + + 183.73 + + 458.87 +
      + Deli + + All Gender + + 155 + + 139.76 + + 342.51 +
      + Eggs + + All Gender + + 42 + + 32.74 + + 80.93 +
      + Frozen Foods + + All Gender + + 352 + + 300.42 + + 738.40 +
      + Meat + + All Gender + + 22 + + 19.76 + + 49.27 +
      + Produce + + All Gender + + 543 + + 456.53 + + 1,145.45 +
      + Seafood + + All Gender + + 34 + + 30.71 + + 75.47 +
      + Snack Foods + + All Gender + + 401 + + 377.01 + + 927.50 +
      + Snacks + + All Gender + + 99 + + 92.80 + + 220.54 +
      + Starchy Foods + + All Gender + + 83 + + 70.61 + + 168.68 +
      + Non-Consumable + + All Gender + + 712 + + 595.08 + + 1,491.87 +
      + Carousel + + All Gender + + 4 + + 3.13 + + 9.20 +
      + Checkout + + All Gender + + 34 + + 34.12 + + 86.21 +
      + Health and Hygiene + + All Gender + + 249 + + 196.08 + + 486.46 +
      + Household + + All Gender + + 361 + + 316.09 + + 795.40 +
      + Periodicals + + All Gender + + 64 + + 45.67 + + 114.60 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/insane-rows-false-true-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/insane-rows-false-true-true-result.html index ab1bbcb1..18045a7a 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/insane-rows-false-true-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/insane-rows-false-true-true-result.html @@ -1,7015 +1,7015 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      - Promotion Media - - Product - - Gender - - Measures -
      - (All) - - Media Type - - (All) - - Product Family - - Product Department - - Product Category - - Product Subcategory - - Brand Name - - Product Name - - (All) - - Gender - - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - All Products - - All Gender - - 266,773 - - 225,627.23 - - 565,238.13 -
      - All Products - - Drink - - All Gender - - 24,597 - - 19,477.23 - - 48,836.21 -
      - Food - - All Gender - - 191,940 - - 163,270.72 - - 409,035.59 -
      - Food - - Baked Goods - - All Gender - - 7,870 - - 6,564.09 - - 16,455.43 -
      - Baking Goods - - All Gender - - 20,245 - - 15,370.61 - - 38,670.41 -
      - Baking Goods - - Baking Goods - - All Gender - - 8,357 - - 6,123.32 - - 15,446.69 -
      - All Gender - - F - - 4,005 - - 2,907.70 - - 7,313.61 -
      - M - - 4,352 - - 3,215.62 - - 8,133.08 -
      - Jams and Jellies - - All Gender - - 11,888 - - 9,247.29 - - 23,223.72 -
      - Jams and Jellies - - Jam - - All Gender - - 2,556 - - 2,132.27 - - 5,401.81 -
      - Jelly - - All Gender - - 2,565 - - 1,830.04 - - 4,609.61 -
      - All Gender - - F - - 1,309 - - 956.94 - - 2,414.94 -
      - M - - 1,256 - - 873.10 - - 2,194.67 -
      - Peanut Butter - - All Gender - - 2,667 - - 2,097.37 - - 5,231.08 -
      - Peanut Butter - - BBB Best - - All Gender - - 556 - - 424.38 - - 1,055.72 -
      - All Gender - - F - - 271 - - 201.08 - - 500.39 -
      - M - - 285 - - 223.30 - - 555.33 -
      - BBB Best - - BBB Best Chunky Peanut Butter - - All Gender - - 188 - - 147.32 - - 370.36 -
      - All Gender - - F - - 107 - - 85.81 - - 210.79 -
      - M - - 81 - - 61.50 - - 159.57 -
      - BBB Best Creamy Peanut Butter - - All Gender - - 201 - - 87.86 - - 221.10 -
      - All Gender - - F - - 99 - - 43.35 - - 108.90 -
      - M - - 102 - - 44.51 - - 112.20 -
      - BBB Best Extra Chunky Peanut Butter - - All Gender - - 167 - - 189.21 - - 464.26 -
      - All Gender - - F - - 65 - - 71.92 - - 180.70 -
      - M - - 102 - - 117.29 - - 283.56 -
      - CDR - - All Gender - - 545 - - 538.88 - - 1,326.30 -
      - Landslide - - All Gender - - 531 - - 256.16 - - 635.29 -
      - Plato - - All Gender - - 520 - - 447.73 - - 1,132.16 -
      - Super - - All Gender - - 515 - - 430.21 - - 1,081.61 -
      - Preserves - - All Gender - - 4,100 - - 3,187.61 - - 7,981.22 -
      - All Gender - - F - - 1,946 - - 1,472.42 - - 3,717.80 -
      - M - - 2,154 - - 1,715.19 - - 4,263.42 -
      - Breakfast Foods - - All Gender - - 3,317 - - 2,756.80 - - 6,941.46 -
      - Canned Foods - - All Gender - - 19,026 - - 15,894.53 - - 39,774.34 -
      - Canned Foods - - Canned Anchovies - - All Gender - - 900 - - 913.88 - - 2,296.38 -
      - Canned Clams - - All Gender - - 882 - - 759.80 - - 1,912.68 -
      - Canned Clams - - Clams - - All Gender - - 882 - - 759.80 - - 1,912.68 -
      - Clams - - Better - - All Gender - - 189 - - 151.14 - - 398.79 -
      - Blue Label - - All Gender - - 165 - - 112.82 - - 278.85 -
      - Bravo - - All Gender - - 184 - - 280.70 - - 708.40 -
      - Just Right - - All Gender - - 177 - - 161.96 - - 394.71 -
      - Pleasant - - All Gender - - 167 - - 53.17 - - 131.93 -
      - Canned Oysters - - All Gender - - 708 - - 571.50 - - 1,442.77 -
      - Canned Sardines - - All Gender - - 819 - - 537.59 - - 1,357.80 -
      - Canned Shrimp - - All Gender - - 804 - - 858.39 - - 2,146.49 -
      - Canned Soup - - All Gender - - 8,006 - - 6,408.29 - - 15,966.10 -
      - Canned Tuna - - All Gender - - 1,710 - - 1,288.52 - - 3,210.76 -
      - Vegetables - - All Gender - - 5,197 - - 4,556.57 - - 11,441.36 -
      - Canned Products - - All Gender - - 1,812 - - 1,317.13 - - 3,314.52 -
      - Dairy - - All Gender - - 12,885 - - 12,228.85 - - 30,508.85 -
      - Deli - - All Gender - - 12,037 - - 10,108.87 - - 25,318.93 -
      - Deli - - Meat - - All Gender - - 9,433 - - 8,215.81 - - 20,616.29 -
      - Meat - - Bologna - - All Gender - - 2,588 - - 2,340.24 - - 5,859.95 -
      - Deli Meats - - All Gender - - 3,339 - - 2,851.18 - - 7,191.24 -
      - All Gender - - F - - 1,653 - - 1,414.49 - - 3,579.34 -
      - M - - 1,686 - - 1,436.69 - - 3,611.90 -
      - Fresh Chicken - - All Gender - - 878 - - 842.85 - - 2,091.52 -
      - Hot Dogs - - All Gender - - 2,628 - - 2,181.55 - - 5,473.58 -
      - Side Dishes - - All Gender - - 2,604 - - 1,893.06 - - 4,702.64 -
      - Eggs - - All Gender - - 4,132 - - 3,684.90 - - 9,200.76 -
      - Frozen Foods - - All Gender - - 26,655 - - 22,030.66 - - 55,207.50 -
      - Meat - - All Gender - - 1,714 - - 1,465.42 - - 3,669.89 -
      - Produce - - All Gender - - 37,792 - - 32,831.33 - - 82,248.42 -
      - Seafood - - All Gender - - 1,764 - - 1,520.70 - - 3,809.14 -
      - Snack Foods - - All Gender - - 30,545 - - 26,963.34 - - 67,609.82 -
      - Snacks - - All Gender - - 6,884 - - 5,827.58 - - 14,550.05 -
      - Starchy Foods - - All Gender - - 5,262 - - 4,705.91 - - 11,756.07 -
      - Non-Consumable - - All Gender - - 50,236 - - 42,879.28 - - 107,366.33 -
      - Non-Consumable - - Carousel - - All Gender - - 841 - - 595.97 - - 1,500.11 -
      - Checkout - - All Gender - - 1,779 - - 1,525.04 - - 3,767.71 -
      - Health and Hygiene - - All Gender - - 16,284 - - 12,972.99 - - 32,571.86 -
      - Household - - All Gender - - 27,038 - - 24,170.73 - - 60,469.89 -
      - Periodicals - - All Gender - - 4,294 - - 3,614.55 - - 9,056.76 -
      - All Media - - Bulk Mail - - All Products - - All Gender - - 4,320 - - 3,740.95 - - 9,349.07 -
      - Cash Register Handout - - All Products - - All Gender - - 6,697 - - 5,715.67 - - 14,321.33 -
      - Daily Paper - - All Products - - All Gender - - 7,738 - - 6,559.23 - - 16,479.81 -
      - Daily Paper, Radio - - All Products - - All Gender - - 6,891 - - 5,668.77 - - 14,169.42 -
      - Daily Paper, Radio, TV - - All Products - - All Gender - - 9,513 - - 8,055.22 - - 20,173.97 -
      - In-Store Coupon - - All Products - - All Gender - - 3,798 - - 3,263.11 - - 8,162.46 -
      - All Products - - Drink - - All Gender - - 345 - - 282.44 - - 708.38 -
      - Food - - All Gender - - 2,737 - - 2,345.57 - - 5,889.34 -
      - Food - - Baked Goods - - All Gender - - 131 - - 114.11 - - 279.11 -
      - Baking Goods - - All Gender - - 308 - - 252.88 - - 632.01 -
      - Baking Goods - - Baking Goods - - All Gender - - 146 - - 103.30 - - 261.44 -
      - Jams and Jellies - - All Gender - - 162 - - 149.58 - - 370.57 -
      - Jams and Jellies - - Jam - - All Gender - - 55 - - 58.16 - - 141.19 -
      - Jelly - - All Gender - - 32 - - 23.96 - - 62.12 -
      - Peanut Butter - - All Gender - - 22 - - 19.54 - - 48.72 -
      - Peanut Butter - - BBB Best - - All Gender - - 7 - - 6.72 - - 16.10 -
      - CDR - - All Gender - - 10 - - 9.81 - - 24.32 -
      - Landslide - - All Gender - -   - -   - -   -
      - Plato - - All Gender - - 3 - - 2.32 - - 6.32 -
      - Super - - All Gender - - 2 - - .69 - - 1.98 -
      - Preserves - - All Gender - - 53 - - 47.92 - - 118.54 -
      - Breakfast Foods - - All Gender - - 59 - - 49.22 - - 125.19 -
      - All Gender - - F - - 33 - - 22.88 - - 54.84 -
      - M - - 26 - - 26.34 - - 70.35 -
      - Canned Foods - - All Gender - - 245 - - 200.61 - - 506.67 -
      - Canned Products - - All Gender - - 15 - - 9.58 - - 26.17 -
      - Dairy - - All Gender - - 166 - - 153.42 - - 372.01 -
      - Deli - - All Gender - - 180 - - 163.58 - - 392.68 -
      - Eggs - - All Gender - - 56 - - 42.51 - - 108.90 -
      - Frozen Foods - - All Gender - - 374 - - 301.63 - - 773.52 -
      - Meat - - All Gender - - 31 - - 23.91 - - 70.35 -
      - Produce - - All Gender - - 563 - - 499.63 - - 1,257.05 -
      - Seafood - - All Gender - - 34 - - 30.06 - - 76.09 -
      - Snack Foods - - All Gender - - 439 - - 390.35 - - 989.13 -
      - Snacks - - All Gender - - 78 - - 63.77 - - 153.02 -
      - Starchy Foods - - All Gender - - 58 - - 50.30 - - 127.44 -
      - Non-Consumable - - All Gender - - 716 - - 635.10 - - 1,564.74 -
      - Non-Consumable - - Carousel - - All Gender - - 17 - - 8.77 - - 24.18 -
      - Checkout - - All Gender - - 23 - - 15.20 - - 40.19 -
      - Health and Hygiene - - All Gender - - 251 - - 193.53 - - 477.21 -
      - Household - - All Gender - - 374 - - 375.66 - - 916.97 -
      - Periodicals - - All Gender - - 51 - - 41.94 - - 106.19 -
      - No Media - - All Products - - All Gender - - 195,448 - - 165,214.85 - - 414,026.92 -
      - All Products - - Drink - - All Gender - - 17,896 - - 14,211.41 - - 35,681.85 -
      - Food - - All Gender - - 140,577 - - 119,469.36 - - 299,356.11 -
      - Food - - Baked Goods - - All Gender - - 5,753 - - 4,775.86 - - 11,972.46 -
      - Baking Goods - - All Gender - - 14,849 - - 11,226.15 - - 28,312.78 -
      - Baking Goods - - Baking Goods - - All Gender - - 5,979 - - 4,347.34 - - 11,002.73 -
      - Jams and Jellies - - All Gender - - 8,870 - - 6,878.81 - - 17,310.05 -
      - Jams and Jellies - - Jam - - All Gender - - 1,883 - - 1,554.13 - - 3,965.74 -
      - Jelly - - All Gender - - 1,936 - - 1,394.32 - - 3,504.71 -
      - Peanut Butter - - All Gender - - 1,984 - - 1,534.19 - - 3,828.01 -
      - Peanut Butter - - BBB Best - - All Gender - - 406 - - 293.97 - - 735.29 -
      - CDR - - All Gender - - 411 - - 401.88 - - 998.12 -
      - Landslide - - All Gender - - 401 - - 195.51 - - 478.44 -
      - Plato - - All Gender - - 384 - - 331.26 - - 832.92 -
      - Super - - All Gender - - 382 - - 311.57 - - 783.24 -
      - Preserves - - All Gender - - 3,067 - - 2,396.16 - - 6,011.59 -
      - Breakfast Foods - - All Gender - - 2,418 - - 1,996.45 - - 5,016.10 -
      - Canned Foods - - All Gender - - 13,861 - - 11,647.47 - - 29,102.79 -
      - Canned Products - - All Gender - - 1,344 - - 960.82 - - 2,424.98 -
      - Dairy - - All Gender - - 9,510 - - 8,981.13 - - 22,454.02 -
      - Deli - - All Gender - - 8,695 - - 7,353.56 - - 18,410.26 -
      - Eggs - - All Gender - - 2,976 - - 2,640.47 - - 6,606.25 -
      - Frozen Foods - - All Gender - - 19,450 - - 16,127.24 - - 40,411.08 -
      - Meat - - All Gender - - 1,236 - - 1,068.07 - - 2,646.00 -
      - Produce - - All Gender - - 27,637 - - 24,036.36 - - 60,203.58 -
      - Seafood - - All Gender - - 1,292 - - 1,114.69 - - 2,774.43 -
      - Snack Foods - - All Gender - - 22,525 - - 19,800.82 - - 49,680.71 -
      - Snacks - - All Gender - - 5,100 - - 4,264.55 - - 10,690.26 -
      - Starchy Foods - - All Gender - - 3,931 - - 3,475.74 - - 8,650.41 -
      - Non-Consumable - - All Gender - - 36,975 - - 31,534.08 - - 78,988.96 -
      - Non-Consumable - - Carousel - - All Gender - - 584 - - 419.65 - - 1,050.75 -
      - Checkout - - All Gender - - 1,305 - - 1,113.97 - - 2,768.66 -
      - Health and Hygiene - - All Gender - - 11,845 - - 9,413.25 - - 23,621.12 -
      - Household - - All Gender - - 20,091 - - 17,929.20 - - 44,881.13 -
      - Periodicals - - All Gender - - 3,150 - - 2,658.00 - - 6,667.30 -
      - Product Attachment - - All Products - - All Gender - - 7,544 - - 6,306.24 - - 15,898.25 -
      - All Products - - Drink - - All Gender - - 713 - - 555.05 - - 1,403.65 -
      - Food - - All Gender - - 5,441 - - 4,571.71 - - 11,525.25 -
      - Food - - Baked Goods - - All Gender - - 213 - - 175.69 - - 445.60 -
      - Baking Goods - - All Gender - - 547 - - 410.31 - - 1,032.59 -
      - Baking Goods - - Baking Goods - - All Gender - - 258 - - 191.48 - - 470.58 -
      - Jams and Jellies - - All Gender - - 289 - - 218.83 - - 562.01 -
      - Jams and Jellies - - Jam - - All Gender - - 66 - - 48.03 - - 128.68 -
      - Jelly - - All Gender - - 45 - - 34.12 - - 90.62 -
      - Peanut Butter - - All Gender - - 63 - - 47.71 - - 122.31 -
      - Peanut Butter - - BBB Best - - All Gender - - 15 - - 14.53 - - 38.46 -
      - CDR - - All Gender - - 13 - - 11.94 - - 30.57 -
      - Landslide - - All Gender - - 12 - - 5.32 - - 14.28 -
      - Plato - - All Gender - - 9 - - 7.16 - - 17.43 -
      - Super - - All Gender - - 14 - - 8.75 - - 21.57 -
      - Preserves - - All Gender - - 115 - - 88.98 - - 220.40 -
      - Breakfast Foods - - All Gender - - 103 - - 87.35 - - 220.75 -
      - Canned Foods - - All Gender - - 564 - - 463.28 - - 1,154.91 -
      - Canned Products - - All Gender - - 60 - - 51.61 - - 124.24 -
      - Dairy - - All Gender - - 355 - - 339.81 - - 849.78 -
      - Deli - - All Gender - - 324 - - 243.64 - - 618.23 -
      - Eggs - - All Gender - - 118 - - 97.43 - - 241.21 -
      - Frozen Foods - - All Gender - - 812 - - 665.48 - - 1,692.11 -
      - Meat - - All Gender - - 54 - - 51.36 - - 127.83 -
      - Produce - - All Gender - - 1,069 - - 909.24 - - 2,287.61 -
      - Seafood - - All Gender - - 45 - - 36.98 - - 100.61 -
      - Snack Foods - - All Gender - - 819 - - 726.73 - - 1,847.28 -
      - Snacks - - All Gender - - 209 - - 186.22 - - 450.03 -
      - Starchy Foods - - All Gender - - 149 - - 126.59 - - 332.47 -
      - Non-Consumable - - All Gender - - 1,390 - - 1,179.48 - - 2,969.35 -
      - Non-Consumable - - Carousel - - All Gender - - 14 - - 7.99 - - 21.21 -
      - Checkout - - All Gender - - 48 - - 40.45 - - 100.61 -
      - Health and Hygiene - - All Gender - - 440 - - 356.54 - - 901.73 -
      - Household - - All Gender - - 777 - - 690.03 - - 1,737.96 -
      - Periodicals - - All Gender - - 111 - - 84.48 - - 207.84 -
      - Radio - - All Products - - All Gender - - 2,454 - - 2,087.51 - - 5,213.61 -
      - All Products - - Drink - - All Gender - - 226 - - 182.85 - - 443.68 -
      - Food - - All Gender - - 1,733 - - 1,485.25 - - 3,727.36 -
      - Food - - Baked Goods - - All Gender - - 83 - - 76.51 - - 186.20 -
      - Baking Goods - - All Gender - - 157 - - 109.10 - - 274.90 -
      - Baking Goods - - Baking Goods - - All Gender - - 63 - - 45.02 - - 110.43 -
      - Jams and Jellies - - All Gender - - 94 - - 64.08 - - 164.47 -
      - Jams and Jellies - - Jam - - All Gender - - 15 - - 10.42 - - 26.94 -
      - Jelly - - All Gender - - 24 - - 14.54 - - 37.49 -
      - Peanut Butter - - All Gender - - 19 - - 16.85 - - 41.82 -
      - Peanut Butter - - BBB Best - - All Gender - - 10 - - 10.58 - - 24.44 -
      - CDR - - All Gender - -   - -   - -   -
      - Landslide - - All Gender - -   - -   - -   -
      - Plato - - All Gender - - 4 - - 3.77 - - 9.80 -
      - Super - - All Gender - - 5 - - 2.50 - - 7.58 -
      - Preserves - - All Gender - - 36 - - 22.28 - - 58.22 -
      - Breakfast Foods - - All Gender - - 25 - - 18.78 - - 50.22 -
      - Canned Foods - - All Gender - - 158 - - 124.79 - - 307.55 -
      - Canned Products - - All Gender - - 22 - - 17.29 - - 43.42 -
      - Dairy - - All Gender - - 112 - - 92.12 - - 216.79 -
      - Deli - - All Gender - - 129 - - 119.14 - - 307.25 -
      - Eggs - - All Gender - - 25 - - 29.97 - - 71.15 -
      - Frozen Foods - - All Gender - - 253 - - 202.71 - - 507.45 -
      - Meat - - All Gender - - 12 - - 11.53 - - 32.85 -
      - Produce - - All Gender - - 336 - - 292.05 - - 738.20 -
      - Seafood - - All Gender - - 15 - - 13.28 - - 35.58 -
      - Snack Foods - - All Gender - - 290 - - 270.59 - - 674.73 -
      - Snacks - - All Gender - - 60 - - 55.67 - - 144.58 -
      - Starchy Foods - - All Gender - - 56 - - 51.72 - - 136.49 -
      - Non-Consumable - - All Gender - - 495 - - 419.41 - - 1,042.57 -
      - Non-Consumable - - Carousel - - All Gender - - 15 - - 11.15 - - 26.85 -
      - Checkout - - All Gender - - 21 - - 17.00 - - 42.74 -
      - Health and Hygiene - - All Gender - - 145 - - 114.84 - - 289.80 -
      - Household - - All Gender - - 258 - - 233.31 - - 575.07 -
      - Periodicals - - All Gender - - 56 - - 43.12 - - 108.11 -
      - Street Handout - - All Products - - All Gender - - 5,753 - - 4,856.54 - - 12,192.90 -
      - All Products - - Drink - - All Gender - - 512 - - 372.68 - - 943.42 -
      - Food - - All Gender - - 4,239 - - 3,650.32 - - 9,151.65 -
      - Food - - Baked Goods - - All Gender - - 160 - - 120.12 - - 301.62 -
      - Baking Goods - - All Gender - - 498 - - 373.67 - - 923.22 -
      - Baking Goods - - Baking Goods - - All Gender - - 200 - - 144.16 - - 357.82 -
      - Jams and Jellies - - All Gender - - 298 - - 229.51 - - 565.40 -
      - Jams and Jellies - - Jam - - All Gender - - 53 - - 44.30 - - 112.95 -
      - Jelly - - All Gender - - 92 - - 63.14 - - 155.59 -
      - Peanut Butter - - All Gender - - 51 - - 51.06 - - 118.90 -
      - Peanut Butter - - BBB Best - - All Gender - - 11 - - 10.85 - - 25.72 -
      - CDR - - All Gender - - 8 - - 9.06 - - 19.73 -
      - Landslide - - All Gender - - 11 - - 6.90 - - 15.54 -
      - Plato - - All Gender - - 9 - - 8.47 - - 20.89 -
      - Super - - All Gender - - 12 - - 15.78 - - 37.02 -
      - Preserves - - All Gender - - 102 - - 71.02 - - 177.96 -
      - Breakfast Foods - - All Gender - - 81 - - 74.32 - - 192.90 -
      - Canned Foods - - All Gender - - 459 - - 413.21 - - 1,021.86 -
      - Canned Products - - All Gender - - 30 - - 19.43 - - 45.68 -
      - Dairy - - All Gender - - 301 - - 285.98 - - 718.61 -
      - Deli - - All Gender - - 305 - - 253.54 - - 638.30 -
      - Eggs - - All Gender - - 66 - - 59.15 - - 156.82 -
      - Frozen Foods - - All Gender - - 612 - - 520.12 - - 1,313.71 -
      - Meat - - All Gender - - 37 - - 29.82 - - 78.24 -
      - Produce - - All Gender - - 745 - - 662.39 - - 1,639.94 -
      - Seafood - - All Gender - - 37 - - 30.12 - - 72.77 -
      - Snack Foods - - All Gender - - 675 - - 600.23 - - 1,515.68 -
      - Snacks - - All Gender - - 144 - - 128.79 - - 321.16 -
      - Starchy Foods - - All Gender - - 89 - - 79.43 - - 211.14 -
      - Non-Consumable - - All Gender - - 1,002 - - 833.53 - - 2,097.83 -
      - Non-Consumable - - Carousel - - All Gender - - 17 - - 13.53 - - 30.98 -
      - Checkout - - All Gender - - 45 - - 34.77 - - 85.38 -
      - Health and Hygiene - - All Gender - - 402 - - 318.03 - - 802.92 -
      - Household - - All Gender - - 501 - - 436.41 - - 1,105.38 -
      - Periodicals - - All Gender - - 37 - - 30.80 - - 73.17 -
      - Sunday Paper - - All Products - - All Gender - - 4,339 - - 3,673.86 - - 9,092.89 -
      - All Products - - Drink - - All Gender - - 430 - - 345.53 - - 856.73 -
      - Food - - All Gender - - 3,106 - - 2,646.47 - - 6,559.46 -
      - Food - - Baked Goods - - All Gender - - 140 - - 110.79 - - 282.55 -
      - Baking Goods - - All Gender - - 338 - - 239.76 - - 603.86 -
      - Baking Goods - - Baking Goods - - All Gender - - 170 - - 118.05 - - 298.79 -
      - Jams and Jellies - - All Gender - - 168 - - 121.71 - - 305.07 -
      - Jams and Jellies - - Jam - - All Gender - - 24 - - 22.35 - - 54.83 -
      - Jelly - - All Gender - - 27 - - 18.20 - - 47.12 -
      - Peanut Butter - - All Gender - - 51 - - 37.67 - - 96.67 -
      - Peanut Butter - - BBB Best - - All Gender - - 10 - - 6.08 - - 16.22 -
      - CDR - - All Gender - - 10 - - 10.47 - - 26.50 -
      - Landslide - - All Gender - - 15 - - 6.20 - - 16.31 -
      - Plato - - All Gender - - 16 - - 14.93 - - 37.64 -
      - Super - - All Gender - -   - -   - -   -
      - Preserves - - All Gender - - 66 - - 43.49 - - 106.45 -
      - Breakfast Foods - - All Gender - - 55 - - 49.80 - - 120.23 -
      - Canned Foods - - All Gender - - 283 - - 249.46 - - 605.11 -
      - Canned Products - - All Gender - - 34 - - 29.65 - - 72.18 -
      - Dairy - - All Gender - - 200 - - 201.94 - - 497.91 -
      - Deli - - All Gender - - 228 - - 188.37 - - 467.53 -
      - Eggs - - All Gender - - 54 - - 47.68 - - 118.44 -
      - Frozen Foods - - All Gender - - 425 - - 330.81 - - 839.15 -
      - Meat - - All Gender - - 18 - - 19.85 - - 52.20 -
      - Produce - - All Gender - - 603 - - 520.95 - - 1,274.70 -
      - Seafood - - All Gender - - 27 - - 26.82 - - 69.49 -
      - Snack Foods - - All Gender - - 469 - - 413.18 - - 1,027.98 -
      - Snacks - - All Gender - - 123 - - 108.50 - - 261.38 -
      - Starchy Foods - - All Gender - - 109 - - 108.91 - - 266.75 -
      - Non-Consumable - - All Gender - - 803 - - 681.86 - - 1,676.70 -
      - Non-Consumable - - Carousel - - All Gender - - 7 - - 6.70 - - 14.68 -
      - Checkout - - All Gender - - 17 - - 13.09 - - 30.89 -
      - Health and Hygiene - - All Gender - - 278 - - 227.06 - - 565.99 -
      - Household - - All Gender - - 420 - - 371.58 - - 911.69 -
      - Periodicals - - All Gender - - 81 - - 63.43 - - 153.45 -
      - Sunday Paper, Radio - - All Products - - All Gender - - 5,945 - - 5,027.31 - - 12,551.96 -
      - All Products - - Drink - - All Gender - - 591 - - 454.03 - - 1,129.94 -
      - Food - - All Gender - - 4,239 - - 3,612.38 - - 9,033.23 -
      - Food - - Baked Goods - - All Gender - - 152 - - 109.11 - - 274.39 -
      - Baking Goods - - All Gender - - 482 - - 367.13 - - 913.84 -
      - Baking Goods - - Baking Goods - - All Gender - - 206 - - 152.72 - - 381.59 -
      - Jams and Jellies - - All Gender - - 276 - - 214.41 - - 532.25 -
      - Jams and Jellies - - Jam - - All Gender - - 52 - - 52.39 - - 126.62 -
      - Jelly - - All Gender - - 74 - - 53.93 - - 135.03 -
      - Peanut Butter - - All Gender - - 64 - - 50.10 - - 126.71 -
      - Peanut Butter - - BBB Best - - All Gender - - 14 - - 11.58 - - 27.40 -
      - CDR - - All Gender - - 17 - - 14.68 - - 41.25 -
      - Landslide - - All Gender - - 14 - - 6.62 - - 17.04 -
      - Plato - - All Gender - - 7 - - 6.91 - - 17.15 -
      - Super - - All Gender - - 12 - - 10.31 - - 23.87 -
      - Preserves - - All Gender - - 86 - - 57.99 - - 143.89 -
      - Breakfast Foods - - All Gender - - 80 - - 62.80 - - 154.04 -
      - Canned Foods - - All Gender - - 456 - - 361.79 - - 914.81 -
      - Canned Products - - All Gender - - 45 - - 39.72 - - 95.88 -
      - Dairy - - All Gender - - 283 - - 296.91 - - 722.75 -
      - Deli - - All Gender - - 252 - - 190.32 - - 479.59 -
      - Eggs - - All Gender - - 114 - - 104.65 - - 256.15 -
      - Frozen Foods - - All Gender - - 599 - - 490.33 - - 1,222.54 -
      - Meat - - All Gender - - 40 - - 31.66 - - 84.76 -
      - Produce - - All Gender - - 858 - - 752.62 - - 1,886.01 -
      - Seafood - - All Gender - - 27 - - 20.66 - - 50.39 -
      - Snack Foods - - All Gender - - 596 - - 555.70 - - 1,402.21 -
      - Snacks - - All Gender - - 147 - - 120.43 - - 304.18 -
      - Starchy Foods - - All Gender - - 108 - - 108.55 - - 271.69 -
      - Non-Consumable - - All Gender - - 1,115 - - 960.90 - - 2,388.79 -
      - Non-Consumable - - Carousel - - All Gender - - 18 - - 10.99 - - 26.94 -
      - Checkout - - All Gender - - 26 - - 24.68 - - 62.14 -
      - Health and Hygiene - - All Gender - - 378 - - 309.37 - - 771.48 -
      - Household - - All Gender - - 585 - - 516.99 - - 1,276.16 -
      - Periodicals - - All Gender - - 108 - - 98.86 - - 252.07 -
      - Sunday Paper, Radio, TV - - All Products - - All Gender - - 2,726 - - 2,341.58 - - 5,819.33 -
      - All Products - - Drink - - All Gender - - 225 - - 163.09 - - 403.51 -
      - Food - - All Gender - - 2,021 - - 1,762.18 - - 4,377.85 -
      - Food - - Baked Goods - - All Gender - - 67 - - 66.17 - - 163.29 -
      - Baking Goods - - All Gender - - 228 - - 182.98 - - 455.90 -
      - Baking Goods - - Baking Goods - - All Gender - - 90 - - 73.09 - - 176.63 -
      - Jams and Jellies - - All Gender - - 138 - - 109.90 - - 279.27 -
      - Jams and Jellies - - Jam - - All Gender - - 37 - - 31.30 - - 78.56 -
      - Jelly - - All Gender - - 27 - - 16.18 - - 39.92 -
      - Peanut Butter - - All Gender - - 30 - - 24.01 - - 64.19 -
      - Peanut Butter - - BBB Best - - All Gender - - 11 - - 9.78 - - 23.86 -
      - CDR - - All Gender - -   - -   - -   -
      - Landslide - - All Gender - - 4 - - 2.39 - - 5.68 -
      - Plato - - All Gender - - 5 - - 3.85 - - 11.60 -
      - Super - - All Gender - - 10 - - 7.99 - - 23.05 -
      - Preserves - - All Gender - - 44 - - 38.41 - - 96.60 -
      - Breakfast Foods - - All Gender - - 38 - - 32.76 - - 89.85 -
      - Canned Foods - - All Gender - - 180 - - 138.77 - - 340.04 -
      - Canned Products - - All Gender - - 14 - - 12.00 - - 28.28 -
      - Dairy - - All Gender - - 121 - - 125.32 - - 305.43 -
      - Deli - - All Gender - - 131 - - 98.93 - - 245.42 -
      - Eggs - - All Gender - - 39 - - 39.57 - - 91.99 -
      - Frozen Foods - - All Gender - - 279 - - 207.59 - - 514.95 -
      - Meat - - All Gender - - 12 - - 11.77 - - 30.23 -
      - Produce - - All Gender - - 411 - - 382.14 - - 943.93 -
      - Seafood - - All Gender - - 31 - - 28.07 - - 69.82 -
      - Snack Foods - - All Gender - - 346 - - 318.26 - - 798.50 -
      - Snacks - - All Gender - - 75 - - 65.49 - - 174.02 -
      - Starchy Foods - - All Gender - - 49 - - 52.37 - - 126.20 -
      - Non-Consumable - - All Gender - - 480 - - 416.30 - - 1,037.97 -
      - Non-Consumable - - Carousel - - All Gender - - 21 - - 11.63 - - 27.92 -
      - Checkout - - All Gender - - 10 - - 8.12 - - 19.80 -
      - Health and Hygiene - - All Gender - - 138 - - 110.35 - - 276.31 -
      - Household - - All Gender - - 262 - - 244.90 - - 608.52 -
      - Periodicals - - All Gender - - 49 - - 41.30 - - 105.42 -
      - TV - - All Products - - All Gender - - 3,607 - - 3,116.40 - - 7,786.21 -
      - All Products - - Drink - - All Gender - - 332 - - 283.18 - - 721.07 -
      - Food - - All Gender - - 2,563 - - 2,238.13 - - 5,573.27 -
      - Food - - Baked Goods - - All Gender - - 114 - - 103.40 - - 262.97 -
      - Baking Goods - - All Gender - - 237 - - 185.55 - - 464.23 -
      - Baking Goods - - Baking Goods - - All Gender - - 95 - - 74.29 - - 190.59 -
      - Jams and Jellies - - All Gender - - 142 - - 111.25 - - 273.64 -
      - Jams and Jellies - - Jam - - All Gender - - 38 - - 32.28 - - 77.58 -
      - Jelly - - All Gender - - 35 - - 24.64 - - 63.38 -
      - Peanut Butter - - All Gender - - 31 - - 21.83 - - 56.80 -
      - Peanut Butter - - BBB Best - - All Gender - -   - -   - -   -
      - CDR - - All Gender - - 11 - - 9.78 - - 27.19 -
      - Landslide - - All Gender - - 7 - - 2.61 - - 7.12 -
      - Plato - - All Gender - - 6 - - 4.95 - - 12.13 -
      - Super - - All Gender - - 7 - - 4.48 - - 10.36 -
      - Preserves - - All Gender - - 38 - - 32.51 - - 75.88 -
      - Breakfast Foods - - All Gender - - 36 - - 30.11 - - 79.89 -
      - Canned Foods - - All Gender - - 240 - - 200.00 - - 519.91 -
      - Canned Products - - All Gender - - 26 - - 15.00 - - 38.65 -
      - Dairy - - All Gender - - 179 - - 183.73 - - 458.87 -
      - Deli - - All Gender - - 155 - - 139.76 - - 342.51 -
      - Eggs - - All Gender - - 42 - - 32.74 - - 80.93 -
      - Frozen Foods - - All Gender - - 352 - - 300.42 - - 738.40 -
      - Meat - - All Gender - - 22 - - 19.76 - - 49.27 -
      - Produce - - All Gender - - 543 - - 456.53 - - 1,145.45 -
      - Seafood - - All Gender - - 34 - - 30.71 - - 75.47 -
      - Snack Foods - - All Gender - - 401 - - 377.01 - - 927.50 -
      - Snacks - - All Gender - - 99 - - 92.80 - - 220.54 -
      - Starchy Foods - - All Gender - - 83 - - 70.61 - - 168.68 -
      - Non-Consumable - - All Gender - - 712 - - 595.08 - - 1,491.87 -
      - Non-Consumable - - Carousel - - All Gender - - 4 - - 3.13 - - 9.20 -
      - Checkout - - All Gender - - 34 - - 34.12 - - 86.21 -
      - Health and Hygiene - - All Gender - - 249 - - 196.08 - - 486.46 -
      - Household - - All Gender - - 361 - - 316.09 - - 795.40 -
      - Periodicals - - All Gender - - 64 - - 45.67 - - 114.60 -
      + Promotion Media + + Product + + Gender + + Measures +
      + (All) + + Media Type + + (All) + + Product Family + + Product Department + + Product Category + + Product Subcategory + + Brand Name + + Product Name + + (All) + + Gender + + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + All Products + + All Gender + + 266,773 + + 225,627.23 + + 565,238.13 +
      + All Products + + Drink + + All Gender + + 24,597 + + 19,477.23 + + 48,836.21 +
      + Food + + All Gender + + 191,940 + + 163,270.72 + + 409,035.59 +
      + Food + + Baked Goods + + All Gender + + 7,870 + + 6,564.09 + + 16,455.43 +
      + Baking Goods + + All Gender + + 20,245 + + 15,370.61 + + 38,670.41 +
      + Baking Goods + + Baking Goods + + All Gender + + 8,357 + + 6,123.32 + + 15,446.69 +
      + All Gender + + F + + 4,005 + + 2,907.70 + + 7,313.61 +
      + M + + 4,352 + + 3,215.62 + + 8,133.08 +
      + Jams and Jellies + + All Gender + + 11,888 + + 9,247.29 + + 23,223.72 +
      + Jams and Jellies + + Jam + + All Gender + + 2,556 + + 2,132.27 + + 5,401.81 +
      + Jelly + + All Gender + + 2,565 + + 1,830.04 + + 4,609.61 +
      + All Gender + + F + + 1,309 + + 956.94 + + 2,414.94 +
      + M + + 1,256 + + 873.10 + + 2,194.67 +
      + Peanut Butter + + All Gender + + 2,667 + + 2,097.37 + + 5,231.08 +
      + Peanut Butter + + BBB Best + + All Gender + + 556 + + 424.38 + + 1,055.72 +
      + All Gender + + F + + 271 + + 201.08 + + 500.39 +
      + M + + 285 + + 223.30 + + 555.33 +
      + BBB Best + + BBB Best Chunky Peanut Butter + + All Gender + + 188 + + 147.32 + + 370.36 +
      + All Gender + + F + + 107 + + 85.81 + + 210.79 +
      + M + + 81 + + 61.50 + + 159.57 +
      + BBB Best Creamy Peanut Butter + + All Gender + + 201 + + 87.86 + + 221.10 +
      + All Gender + + F + + 99 + + 43.35 + + 108.90 +
      + M + + 102 + + 44.51 + + 112.20 +
      + BBB Best Extra Chunky Peanut Butter + + All Gender + + 167 + + 189.21 + + 464.26 +
      + All Gender + + F + + 65 + + 71.92 + + 180.70 +
      + M + + 102 + + 117.29 + + 283.56 +
      + CDR + + All Gender + + 545 + + 538.88 + + 1,326.30 +
      + Landslide + + All Gender + + 531 + + 256.16 + + 635.29 +
      + Plato + + All Gender + + 520 + + 447.73 + + 1,132.16 +
      + Super + + All Gender + + 515 + + 430.21 + + 1,081.61 +
      + Preserves + + All Gender + + 4,100 + + 3,187.61 + + 7,981.22 +
      + All Gender + + F + + 1,946 + + 1,472.42 + + 3,717.80 +
      + M + + 2,154 + + 1,715.19 + + 4,263.42 +
      + Breakfast Foods + + All Gender + + 3,317 + + 2,756.80 + + 6,941.46 +
      + Canned Foods + + All Gender + + 19,026 + + 15,894.53 + + 39,774.34 +
      + Canned Foods + + Canned Anchovies + + All Gender + + 900 + + 913.88 + + 2,296.38 +
      + Canned Clams + + All Gender + + 882 + + 759.80 + + 1,912.68 +
      + Canned Clams + + Clams + + All Gender + + 882 + + 759.80 + + 1,912.68 +
      + Clams + + Better + + All Gender + + 189 + + 151.14 + + 398.79 +
      + Blue Label + + All Gender + + 165 + + 112.82 + + 278.85 +
      + Bravo + + All Gender + + 184 + + 280.70 + + 708.40 +
      + Just Right + + All Gender + + 177 + + 161.96 + + 394.71 +
      + Pleasant + + All Gender + + 167 + + 53.17 + + 131.93 +
      + Canned Oysters + + All Gender + + 708 + + 571.50 + + 1,442.77 +
      + Canned Sardines + + All Gender + + 819 + + 537.59 + + 1,357.80 +
      + Canned Shrimp + + All Gender + + 804 + + 858.39 + + 2,146.49 +
      + Canned Soup + + All Gender + + 8,006 + + 6,408.29 + + 15,966.10 +
      + Canned Tuna + + All Gender + + 1,710 + + 1,288.52 + + 3,210.76 +
      + Vegetables + + All Gender + + 5,197 + + 4,556.57 + + 11,441.36 +
      + Canned Products + + All Gender + + 1,812 + + 1,317.13 + + 3,314.52 +
      + Dairy + + All Gender + + 12,885 + + 12,228.85 + + 30,508.85 +
      + Deli + + All Gender + + 12,037 + + 10,108.87 + + 25,318.93 +
      + Deli + + Meat + + All Gender + + 9,433 + + 8,215.81 + + 20,616.29 +
      + Meat + + Bologna + + All Gender + + 2,588 + + 2,340.24 + + 5,859.95 +
      + Deli Meats + + All Gender + + 3,339 + + 2,851.18 + + 7,191.24 +
      + All Gender + + F + + 1,653 + + 1,414.49 + + 3,579.34 +
      + M + + 1,686 + + 1,436.69 + + 3,611.90 +
      + Fresh Chicken + + All Gender + + 878 + + 842.85 + + 2,091.52 +
      + Hot Dogs + + All Gender + + 2,628 + + 2,181.55 + + 5,473.58 +
      + Side Dishes + + All Gender + + 2,604 + + 1,893.06 + + 4,702.64 +
      + Eggs + + All Gender + + 4,132 + + 3,684.90 + + 9,200.76 +
      + Frozen Foods + + All Gender + + 26,655 + + 22,030.66 + + 55,207.50 +
      + Meat + + All Gender + + 1,714 + + 1,465.42 + + 3,669.89 +
      + Produce + + All Gender + + 37,792 + + 32,831.33 + + 82,248.42 +
      + Seafood + + All Gender + + 1,764 + + 1,520.70 + + 3,809.14 +
      + Snack Foods + + All Gender + + 30,545 + + 26,963.34 + + 67,609.82 +
      + Snacks + + All Gender + + 6,884 + + 5,827.58 + + 14,550.05 +
      + Starchy Foods + + All Gender + + 5,262 + + 4,705.91 + + 11,756.07 +
      + Non-Consumable + + All Gender + + 50,236 + + 42,879.28 + + 107,366.33 +
      + Non-Consumable + + Carousel + + All Gender + + 841 + + 595.97 + + 1,500.11 +
      + Checkout + + All Gender + + 1,779 + + 1,525.04 + + 3,767.71 +
      + Health and Hygiene + + All Gender + + 16,284 + + 12,972.99 + + 32,571.86 +
      + Household + + All Gender + + 27,038 + + 24,170.73 + + 60,469.89 +
      + Periodicals + + All Gender + + 4,294 + + 3,614.55 + + 9,056.76 +
      + All Media + + Bulk Mail + + All Products + + All Gender + + 4,320 + + 3,740.95 + + 9,349.07 +
      + Cash Register Handout + + All Products + + All Gender + + 6,697 + + 5,715.67 + + 14,321.33 +
      + Daily Paper + + All Products + + All Gender + + 7,738 + + 6,559.23 + + 16,479.81 +
      + Daily Paper, Radio + + All Products + + All Gender + + 6,891 + + 5,668.77 + + 14,169.42 +
      + Daily Paper, Radio, TV + + All Products + + All Gender + + 9,513 + + 8,055.22 + + 20,173.97 +
      + In-Store Coupon + + All Products + + All Gender + + 3,798 + + 3,263.11 + + 8,162.46 +
      + All Products + + Drink + + All Gender + + 345 + + 282.44 + + 708.38 +
      + Food + + All Gender + + 2,737 + + 2,345.57 + + 5,889.34 +
      + Food + + Baked Goods + + All Gender + + 131 + + 114.11 + + 279.11 +
      + Baking Goods + + All Gender + + 308 + + 252.88 + + 632.01 +
      + Baking Goods + + Baking Goods + + All Gender + + 146 + + 103.30 + + 261.44 +
      + Jams and Jellies + + All Gender + + 162 + + 149.58 + + 370.57 +
      + Jams and Jellies + + Jam + + All Gender + + 55 + + 58.16 + + 141.19 +
      + Jelly + + All Gender + + 32 + + 23.96 + + 62.12 +
      + Peanut Butter + + All Gender + + 22 + + 19.54 + + 48.72 +
      + Peanut Butter + + BBB Best + + All Gender + + 7 + + 6.72 + + 16.10 +
      + CDR + + All Gender + + 10 + + 9.81 + + 24.32 +
      + Landslide + + All Gender + +   + +   + +   +
      + Plato + + All Gender + + 3 + + 2.32 + + 6.32 +
      + Super + + All Gender + + 2 + + .69 + + 1.98 +
      + Preserves + + All Gender + + 53 + + 47.92 + + 118.54 +
      + Breakfast Foods + + All Gender + + 59 + + 49.22 + + 125.19 +
      + All Gender + + F + + 33 + + 22.88 + + 54.84 +
      + M + + 26 + + 26.34 + + 70.35 +
      + Canned Foods + + All Gender + + 245 + + 200.61 + + 506.67 +
      + Canned Products + + All Gender + + 15 + + 9.58 + + 26.17 +
      + Dairy + + All Gender + + 166 + + 153.42 + + 372.01 +
      + Deli + + All Gender + + 180 + + 163.58 + + 392.68 +
      + Eggs + + All Gender + + 56 + + 42.51 + + 108.90 +
      + Frozen Foods + + All Gender + + 374 + + 301.63 + + 773.52 +
      + Meat + + All Gender + + 31 + + 23.91 + + 70.35 +
      + Produce + + All Gender + + 563 + + 499.63 + + 1,257.05 +
      + Seafood + + All Gender + + 34 + + 30.06 + + 76.09 +
      + Snack Foods + + All Gender + + 439 + + 390.35 + + 989.13 +
      + Snacks + + All Gender + + 78 + + 63.77 + + 153.02 +
      + Starchy Foods + + All Gender + + 58 + + 50.30 + + 127.44 +
      + Non-Consumable + + All Gender + + 716 + + 635.10 + + 1,564.74 +
      + Non-Consumable + + Carousel + + All Gender + + 17 + + 8.77 + + 24.18 +
      + Checkout + + All Gender + + 23 + + 15.20 + + 40.19 +
      + Health and Hygiene + + All Gender + + 251 + + 193.53 + + 477.21 +
      + Household + + All Gender + + 374 + + 375.66 + + 916.97 +
      + Periodicals + + All Gender + + 51 + + 41.94 + + 106.19 +
      + No Media + + All Products + + All Gender + + 195,448 + + 165,214.85 + + 414,026.92 +
      + All Products + + Drink + + All Gender + + 17,896 + + 14,211.41 + + 35,681.85 +
      + Food + + All Gender + + 140,577 + + 119,469.36 + + 299,356.11 +
      + Food + + Baked Goods + + All Gender + + 5,753 + + 4,775.86 + + 11,972.46 +
      + Baking Goods + + All Gender + + 14,849 + + 11,226.15 + + 28,312.78 +
      + Baking Goods + + Baking Goods + + All Gender + + 5,979 + + 4,347.34 + + 11,002.73 +
      + Jams and Jellies + + All Gender + + 8,870 + + 6,878.81 + + 17,310.05 +
      + Jams and Jellies + + Jam + + All Gender + + 1,883 + + 1,554.13 + + 3,965.74 +
      + Jelly + + All Gender + + 1,936 + + 1,394.32 + + 3,504.71 +
      + Peanut Butter + + All Gender + + 1,984 + + 1,534.19 + + 3,828.01 +
      + Peanut Butter + + BBB Best + + All Gender + + 406 + + 293.97 + + 735.29 +
      + CDR + + All Gender + + 411 + + 401.88 + + 998.12 +
      + Landslide + + All Gender + + 401 + + 195.51 + + 478.44 +
      + Plato + + All Gender + + 384 + + 331.26 + + 832.92 +
      + Super + + All Gender + + 382 + + 311.57 + + 783.24 +
      + Preserves + + All Gender + + 3,067 + + 2,396.16 + + 6,011.59 +
      + Breakfast Foods + + All Gender + + 2,418 + + 1,996.45 + + 5,016.10 +
      + Canned Foods + + All Gender + + 13,861 + + 11,647.47 + + 29,102.79 +
      + Canned Products + + All Gender + + 1,344 + + 960.82 + + 2,424.98 +
      + Dairy + + All Gender + + 9,510 + + 8,981.13 + + 22,454.02 +
      + Deli + + All Gender + + 8,695 + + 7,353.56 + + 18,410.26 +
      + Eggs + + All Gender + + 2,976 + + 2,640.47 + + 6,606.25 +
      + Frozen Foods + + All Gender + + 19,450 + + 16,127.24 + + 40,411.08 +
      + Meat + + All Gender + + 1,236 + + 1,068.07 + + 2,646.00 +
      + Produce + + All Gender + + 27,637 + + 24,036.36 + + 60,203.58 +
      + Seafood + + All Gender + + 1,292 + + 1,114.69 + + 2,774.43 +
      + Snack Foods + + All Gender + + 22,525 + + 19,800.82 + + 49,680.71 +
      + Snacks + + All Gender + + 5,100 + + 4,264.55 + + 10,690.26 +
      + Starchy Foods + + All Gender + + 3,931 + + 3,475.74 + + 8,650.41 +
      + Non-Consumable + + All Gender + + 36,975 + + 31,534.08 + + 78,988.96 +
      + Non-Consumable + + Carousel + + All Gender + + 584 + + 419.65 + + 1,050.75 +
      + Checkout + + All Gender + + 1,305 + + 1,113.97 + + 2,768.66 +
      + Health and Hygiene + + All Gender + + 11,845 + + 9,413.25 + + 23,621.12 +
      + Household + + All Gender + + 20,091 + + 17,929.20 + + 44,881.13 +
      + Periodicals + + All Gender + + 3,150 + + 2,658.00 + + 6,667.30 +
      + Product Attachment + + All Products + + All Gender + + 7,544 + + 6,306.24 + + 15,898.25 +
      + All Products + + Drink + + All Gender + + 713 + + 555.05 + + 1,403.65 +
      + Food + + All Gender + + 5,441 + + 4,571.71 + + 11,525.25 +
      + Food + + Baked Goods + + All Gender + + 213 + + 175.69 + + 445.60 +
      + Baking Goods + + All Gender + + 547 + + 410.31 + + 1,032.59 +
      + Baking Goods + + Baking Goods + + All Gender + + 258 + + 191.48 + + 470.58 +
      + Jams and Jellies + + All Gender + + 289 + + 218.83 + + 562.01 +
      + Jams and Jellies + + Jam + + All Gender + + 66 + + 48.03 + + 128.68 +
      + Jelly + + All Gender + + 45 + + 34.12 + + 90.62 +
      + Peanut Butter + + All Gender + + 63 + + 47.71 + + 122.31 +
      + Peanut Butter + + BBB Best + + All Gender + + 15 + + 14.53 + + 38.46 +
      + CDR + + All Gender + + 13 + + 11.94 + + 30.57 +
      + Landslide + + All Gender + + 12 + + 5.32 + + 14.28 +
      + Plato + + All Gender + + 9 + + 7.16 + + 17.43 +
      + Super + + All Gender + + 14 + + 8.75 + + 21.57 +
      + Preserves + + All Gender + + 115 + + 88.98 + + 220.40 +
      + Breakfast Foods + + All Gender + + 103 + + 87.35 + + 220.75 +
      + Canned Foods + + All Gender + + 564 + + 463.28 + + 1,154.91 +
      + Canned Products + + All Gender + + 60 + + 51.61 + + 124.24 +
      + Dairy + + All Gender + + 355 + + 339.81 + + 849.78 +
      + Deli + + All Gender + + 324 + + 243.64 + + 618.23 +
      + Eggs + + All Gender + + 118 + + 97.43 + + 241.21 +
      + Frozen Foods + + All Gender + + 812 + + 665.48 + + 1,692.11 +
      + Meat + + All Gender + + 54 + + 51.36 + + 127.83 +
      + Produce + + All Gender + + 1,069 + + 909.24 + + 2,287.61 +
      + Seafood + + All Gender + + 45 + + 36.98 + + 100.61 +
      + Snack Foods + + All Gender + + 819 + + 726.73 + + 1,847.28 +
      + Snacks + + All Gender + + 209 + + 186.22 + + 450.03 +
      + Starchy Foods + + All Gender + + 149 + + 126.59 + + 332.47 +
      + Non-Consumable + + All Gender + + 1,390 + + 1,179.48 + + 2,969.35 +
      + Non-Consumable + + Carousel + + All Gender + + 14 + + 7.99 + + 21.21 +
      + Checkout + + All Gender + + 48 + + 40.45 + + 100.61 +
      + Health and Hygiene + + All Gender + + 440 + + 356.54 + + 901.73 +
      + Household + + All Gender + + 777 + + 690.03 + + 1,737.96 +
      + Periodicals + + All Gender + + 111 + + 84.48 + + 207.84 +
      + Radio + + All Products + + All Gender + + 2,454 + + 2,087.51 + + 5,213.61 +
      + All Products + + Drink + + All Gender + + 226 + + 182.85 + + 443.68 +
      + Food + + All Gender + + 1,733 + + 1,485.25 + + 3,727.36 +
      + Food + + Baked Goods + + All Gender + + 83 + + 76.51 + + 186.20 +
      + Baking Goods + + All Gender + + 157 + + 109.10 + + 274.90 +
      + Baking Goods + + Baking Goods + + All Gender + + 63 + + 45.02 + + 110.43 +
      + Jams and Jellies + + All Gender + + 94 + + 64.08 + + 164.47 +
      + Jams and Jellies + + Jam + + All Gender + + 15 + + 10.42 + + 26.94 +
      + Jelly + + All Gender + + 24 + + 14.54 + + 37.49 +
      + Peanut Butter + + All Gender + + 19 + + 16.85 + + 41.82 +
      + Peanut Butter + + BBB Best + + All Gender + + 10 + + 10.58 + + 24.44 +
      + CDR + + All Gender + +   + +   + +   +
      + Landslide + + All Gender + +   + +   + +   +
      + Plato + + All Gender + + 4 + + 3.77 + + 9.80 +
      + Super + + All Gender + + 5 + + 2.50 + + 7.58 +
      + Preserves + + All Gender + + 36 + + 22.28 + + 58.22 +
      + Breakfast Foods + + All Gender + + 25 + + 18.78 + + 50.22 +
      + Canned Foods + + All Gender + + 158 + + 124.79 + + 307.55 +
      + Canned Products + + All Gender + + 22 + + 17.29 + + 43.42 +
      + Dairy + + All Gender + + 112 + + 92.12 + + 216.79 +
      + Deli + + All Gender + + 129 + + 119.14 + + 307.25 +
      + Eggs + + All Gender + + 25 + + 29.97 + + 71.15 +
      + Frozen Foods + + All Gender + + 253 + + 202.71 + + 507.45 +
      + Meat + + All Gender + + 12 + + 11.53 + + 32.85 +
      + Produce + + All Gender + + 336 + + 292.05 + + 738.20 +
      + Seafood + + All Gender + + 15 + + 13.28 + + 35.58 +
      + Snack Foods + + All Gender + + 290 + + 270.59 + + 674.73 +
      + Snacks + + All Gender + + 60 + + 55.67 + + 144.58 +
      + Starchy Foods + + All Gender + + 56 + + 51.72 + + 136.49 +
      + Non-Consumable + + All Gender + + 495 + + 419.41 + + 1,042.57 +
      + Non-Consumable + + Carousel + + All Gender + + 15 + + 11.15 + + 26.85 +
      + Checkout + + All Gender + + 21 + + 17.00 + + 42.74 +
      + Health and Hygiene + + All Gender + + 145 + + 114.84 + + 289.80 +
      + Household + + All Gender + + 258 + + 233.31 + + 575.07 +
      + Periodicals + + All Gender + + 56 + + 43.12 + + 108.11 +
      + Street Handout + + All Products + + All Gender + + 5,753 + + 4,856.54 + + 12,192.90 +
      + All Products + + Drink + + All Gender + + 512 + + 372.68 + + 943.42 +
      + Food + + All Gender + + 4,239 + + 3,650.32 + + 9,151.65 +
      + Food + + Baked Goods + + All Gender + + 160 + + 120.12 + + 301.62 +
      + Baking Goods + + All Gender + + 498 + + 373.67 + + 923.22 +
      + Baking Goods + + Baking Goods + + All Gender + + 200 + + 144.16 + + 357.82 +
      + Jams and Jellies + + All Gender + + 298 + + 229.51 + + 565.40 +
      + Jams and Jellies + + Jam + + All Gender + + 53 + + 44.30 + + 112.95 +
      + Jelly + + All Gender + + 92 + + 63.14 + + 155.59 +
      + Peanut Butter + + All Gender + + 51 + + 51.06 + + 118.90 +
      + Peanut Butter + + BBB Best + + All Gender + + 11 + + 10.85 + + 25.72 +
      + CDR + + All Gender + + 8 + + 9.06 + + 19.73 +
      + Landslide + + All Gender + + 11 + + 6.90 + + 15.54 +
      + Plato + + All Gender + + 9 + + 8.47 + + 20.89 +
      + Super + + All Gender + + 12 + + 15.78 + + 37.02 +
      + Preserves + + All Gender + + 102 + + 71.02 + + 177.96 +
      + Breakfast Foods + + All Gender + + 81 + + 74.32 + + 192.90 +
      + Canned Foods + + All Gender + + 459 + + 413.21 + + 1,021.86 +
      + Canned Products + + All Gender + + 30 + + 19.43 + + 45.68 +
      + Dairy + + All Gender + + 301 + + 285.98 + + 718.61 +
      + Deli + + All Gender + + 305 + + 253.54 + + 638.30 +
      + Eggs + + All Gender + + 66 + + 59.15 + + 156.82 +
      + Frozen Foods + + All Gender + + 612 + + 520.12 + + 1,313.71 +
      + Meat + + All Gender + + 37 + + 29.82 + + 78.24 +
      + Produce + + All Gender + + 745 + + 662.39 + + 1,639.94 +
      + Seafood + + All Gender + + 37 + + 30.12 + + 72.77 +
      + Snack Foods + + All Gender + + 675 + + 600.23 + + 1,515.68 +
      + Snacks + + All Gender + + 144 + + 128.79 + + 321.16 +
      + Starchy Foods + + All Gender + + 89 + + 79.43 + + 211.14 +
      + Non-Consumable + + All Gender + + 1,002 + + 833.53 + + 2,097.83 +
      + Non-Consumable + + Carousel + + All Gender + + 17 + + 13.53 + + 30.98 +
      + Checkout + + All Gender + + 45 + + 34.77 + + 85.38 +
      + Health and Hygiene + + All Gender + + 402 + + 318.03 + + 802.92 +
      + Household + + All Gender + + 501 + + 436.41 + + 1,105.38 +
      + Periodicals + + All Gender + + 37 + + 30.80 + + 73.17 +
      + Sunday Paper + + All Products + + All Gender + + 4,339 + + 3,673.86 + + 9,092.89 +
      + All Products + + Drink + + All Gender + + 430 + + 345.53 + + 856.73 +
      + Food + + All Gender + + 3,106 + + 2,646.47 + + 6,559.46 +
      + Food + + Baked Goods + + All Gender + + 140 + + 110.79 + + 282.55 +
      + Baking Goods + + All Gender + + 338 + + 239.76 + + 603.86 +
      + Baking Goods + + Baking Goods + + All Gender + + 170 + + 118.05 + + 298.79 +
      + Jams and Jellies + + All Gender + + 168 + + 121.71 + + 305.07 +
      + Jams and Jellies + + Jam + + All Gender + + 24 + + 22.35 + + 54.83 +
      + Jelly + + All Gender + + 27 + + 18.20 + + 47.12 +
      + Peanut Butter + + All Gender + + 51 + + 37.67 + + 96.67 +
      + Peanut Butter + + BBB Best + + All Gender + + 10 + + 6.08 + + 16.22 +
      + CDR + + All Gender + + 10 + + 10.47 + + 26.50 +
      + Landslide + + All Gender + + 15 + + 6.20 + + 16.31 +
      + Plato + + All Gender + + 16 + + 14.93 + + 37.64 +
      + Super + + All Gender + +   + +   + +   +
      + Preserves + + All Gender + + 66 + + 43.49 + + 106.45 +
      + Breakfast Foods + + All Gender + + 55 + + 49.80 + + 120.23 +
      + Canned Foods + + All Gender + + 283 + + 249.46 + + 605.11 +
      + Canned Products + + All Gender + + 34 + + 29.65 + + 72.18 +
      + Dairy + + All Gender + + 200 + + 201.94 + + 497.91 +
      + Deli + + All Gender + + 228 + + 188.37 + + 467.53 +
      + Eggs + + All Gender + + 54 + + 47.68 + + 118.44 +
      + Frozen Foods + + All Gender + + 425 + + 330.81 + + 839.15 +
      + Meat + + All Gender + + 18 + + 19.85 + + 52.20 +
      + Produce + + All Gender + + 603 + + 520.95 + + 1,274.70 +
      + Seafood + + All Gender + + 27 + + 26.82 + + 69.49 +
      + Snack Foods + + All Gender + + 469 + + 413.18 + + 1,027.98 +
      + Snacks + + All Gender + + 123 + + 108.50 + + 261.38 +
      + Starchy Foods + + All Gender + + 109 + + 108.91 + + 266.75 +
      + Non-Consumable + + All Gender + + 803 + + 681.86 + + 1,676.70 +
      + Non-Consumable + + Carousel + + All Gender + + 7 + + 6.70 + + 14.68 +
      + Checkout + + All Gender + + 17 + + 13.09 + + 30.89 +
      + Health and Hygiene + + All Gender + + 278 + + 227.06 + + 565.99 +
      + Household + + All Gender + + 420 + + 371.58 + + 911.69 +
      + Periodicals + + All Gender + + 81 + + 63.43 + + 153.45 +
      + Sunday Paper, Radio + + All Products + + All Gender + + 5,945 + + 5,027.31 + + 12,551.96 +
      + All Products + + Drink + + All Gender + + 591 + + 454.03 + + 1,129.94 +
      + Food + + All Gender + + 4,239 + + 3,612.38 + + 9,033.23 +
      + Food + + Baked Goods + + All Gender + + 152 + + 109.11 + + 274.39 +
      + Baking Goods + + All Gender + + 482 + + 367.13 + + 913.84 +
      + Baking Goods + + Baking Goods + + All Gender + + 206 + + 152.72 + + 381.59 +
      + Jams and Jellies + + All Gender + + 276 + + 214.41 + + 532.25 +
      + Jams and Jellies + + Jam + + All Gender + + 52 + + 52.39 + + 126.62 +
      + Jelly + + All Gender + + 74 + + 53.93 + + 135.03 +
      + Peanut Butter + + All Gender + + 64 + + 50.10 + + 126.71 +
      + Peanut Butter + + BBB Best + + All Gender + + 14 + + 11.58 + + 27.40 +
      + CDR + + All Gender + + 17 + + 14.68 + + 41.25 +
      + Landslide + + All Gender + + 14 + + 6.62 + + 17.04 +
      + Plato + + All Gender + + 7 + + 6.91 + + 17.15 +
      + Super + + All Gender + + 12 + + 10.31 + + 23.87 +
      + Preserves + + All Gender + + 86 + + 57.99 + + 143.89 +
      + Breakfast Foods + + All Gender + + 80 + + 62.80 + + 154.04 +
      + Canned Foods + + All Gender + + 456 + + 361.79 + + 914.81 +
      + Canned Products + + All Gender + + 45 + + 39.72 + + 95.88 +
      + Dairy + + All Gender + + 283 + + 296.91 + + 722.75 +
      + Deli + + All Gender + + 252 + + 190.32 + + 479.59 +
      + Eggs + + All Gender + + 114 + + 104.65 + + 256.15 +
      + Frozen Foods + + All Gender + + 599 + + 490.33 + + 1,222.54 +
      + Meat + + All Gender + + 40 + + 31.66 + + 84.76 +
      + Produce + + All Gender + + 858 + + 752.62 + + 1,886.01 +
      + Seafood + + All Gender + + 27 + + 20.66 + + 50.39 +
      + Snack Foods + + All Gender + + 596 + + 555.70 + + 1,402.21 +
      + Snacks + + All Gender + + 147 + + 120.43 + + 304.18 +
      + Starchy Foods + + All Gender + + 108 + + 108.55 + + 271.69 +
      + Non-Consumable + + All Gender + + 1,115 + + 960.90 + + 2,388.79 +
      + Non-Consumable + + Carousel + + All Gender + + 18 + + 10.99 + + 26.94 +
      + Checkout + + All Gender + + 26 + + 24.68 + + 62.14 +
      + Health and Hygiene + + All Gender + + 378 + + 309.37 + + 771.48 +
      + Household + + All Gender + + 585 + + 516.99 + + 1,276.16 +
      + Periodicals + + All Gender + + 108 + + 98.86 + + 252.07 +
      + Sunday Paper, Radio, TV + + All Products + + All Gender + + 2,726 + + 2,341.58 + + 5,819.33 +
      + All Products + + Drink + + All Gender + + 225 + + 163.09 + + 403.51 +
      + Food + + All Gender + + 2,021 + + 1,762.18 + + 4,377.85 +
      + Food + + Baked Goods + + All Gender + + 67 + + 66.17 + + 163.29 +
      + Baking Goods + + All Gender + + 228 + + 182.98 + + 455.90 +
      + Baking Goods + + Baking Goods + + All Gender + + 90 + + 73.09 + + 176.63 +
      + Jams and Jellies + + All Gender + + 138 + + 109.90 + + 279.27 +
      + Jams and Jellies + + Jam + + All Gender + + 37 + + 31.30 + + 78.56 +
      + Jelly + + All Gender + + 27 + + 16.18 + + 39.92 +
      + Peanut Butter + + All Gender + + 30 + + 24.01 + + 64.19 +
      + Peanut Butter + + BBB Best + + All Gender + + 11 + + 9.78 + + 23.86 +
      + CDR + + All Gender + +   + +   + +   +
      + Landslide + + All Gender + + 4 + + 2.39 + + 5.68 +
      + Plato + + All Gender + + 5 + + 3.85 + + 11.60 +
      + Super + + All Gender + + 10 + + 7.99 + + 23.05 +
      + Preserves + + All Gender + + 44 + + 38.41 + + 96.60 +
      + Breakfast Foods + + All Gender + + 38 + + 32.76 + + 89.85 +
      + Canned Foods + + All Gender + + 180 + + 138.77 + + 340.04 +
      + Canned Products + + All Gender + + 14 + + 12.00 + + 28.28 +
      + Dairy + + All Gender + + 121 + + 125.32 + + 305.43 +
      + Deli + + All Gender + + 131 + + 98.93 + + 245.42 +
      + Eggs + + All Gender + + 39 + + 39.57 + + 91.99 +
      + Frozen Foods + + All Gender + + 279 + + 207.59 + + 514.95 +
      + Meat + + All Gender + + 12 + + 11.77 + + 30.23 +
      + Produce + + All Gender + + 411 + + 382.14 + + 943.93 +
      + Seafood + + All Gender + + 31 + + 28.07 + + 69.82 +
      + Snack Foods + + All Gender + + 346 + + 318.26 + + 798.50 +
      + Snacks + + All Gender + + 75 + + 65.49 + + 174.02 +
      + Starchy Foods + + All Gender + + 49 + + 52.37 + + 126.20 +
      + Non-Consumable + + All Gender + + 480 + + 416.30 + + 1,037.97 +
      + Non-Consumable + + Carousel + + All Gender + + 21 + + 11.63 + + 27.92 +
      + Checkout + + All Gender + + 10 + + 8.12 + + 19.80 +
      + Health and Hygiene + + All Gender + + 138 + + 110.35 + + 276.31 +
      + Household + + All Gender + + 262 + + 244.90 + + 608.52 +
      + Periodicals + + All Gender + + 49 + + 41.30 + + 105.42 +
      + TV + + All Products + + All Gender + + 3,607 + + 3,116.40 + + 7,786.21 +
      + All Products + + Drink + + All Gender + + 332 + + 283.18 + + 721.07 +
      + Food + + All Gender + + 2,563 + + 2,238.13 + + 5,573.27 +
      + Food + + Baked Goods + + All Gender + + 114 + + 103.40 + + 262.97 +
      + Baking Goods + + All Gender + + 237 + + 185.55 + + 464.23 +
      + Baking Goods + + Baking Goods + + All Gender + + 95 + + 74.29 + + 190.59 +
      + Jams and Jellies + + All Gender + + 142 + + 111.25 + + 273.64 +
      + Jams and Jellies + + Jam + + All Gender + + 38 + + 32.28 + + 77.58 +
      + Jelly + + All Gender + + 35 + + 24.64 + + 63.38 +
      + Peanut Butter + + All Gender + + 31 + + 21.83 + + 56.80 +
      + Peanut Butter + + BBB Best + + All Gender + +   + +   + +   +
      + CDR + + All Gender + + 11 + + 9.78 + + 27.19 +
      + Landslide + + All Gender + + 7 + + 2.61 + + 7.12 +
      + Plato + + All Gender + + 6 + + 4.95 + + 12.13 +
      + Super + + All Gender + + 7 + + 4.48 + + 10.36 +
      + Preserves + + All Gender + + 38 + + 32.51 + + 75.88 +
      + Breakfast Foods + + All Gender + + 36 + + 30.11 + + 79.89 +
      + Canned Foods + + All Gender + + 240 + + 200.00 + + 519.91 +
      + Canned Products + + All Gender + + 26 + + 15.00 + + 38.65 +
      + Dairy + + All Gender + + 179 + + 183.73 + + 458.87 +
      + Deli + + All Gender + + 155 + + 139.76 + + 342.51 +
      + Eggs + + All Gender + + 42 + + 32.74 + + 80.93 +
      + Frozen Foods + + All Gender + + 352 + + 300.42 + + 738.40 +
      + Meat + + All Gender + + 22 + + 19.76 + + 49.27 +
      + Produce + + All Gender + + 543 + + 456.53 + + 1,145.45 +
      + Seafood + + All Gender + + 34 + + 30.71 + + 75.47 +
      + Snack Foods + + All Gender + + 401 + + 377.01 + + 927.50 +
      + Snacks + + All Gender + + 99 + + 92.80 + + 220.54 +
      + Starchy Foods + + All Gender + + 83 + + 70.61 + + 168.68 +
      + Non-Consumable + + All Gender + + 712 + + 595.08 + + 1,491.87 +
      + Non-Consumable + + Carousel + + All Gender + + 4 + + 3.13 + + 9.20 +
      + Checkout + + All Gender + + 34 + + 34.12 + + 86.21 +
      + Health and Hygiene + + All Gender + + 249 + + 196.08 + + 486.46 +
      + Household + + All Gender + + 361 + + 316.09 + + 795.40 +
      + Periodicals + + All Gender + + 64 + + 45.67 + + 114.60 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/insane-rows-true-false-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/insane-rows-true-false-false-result.html index b2f5171c..5c5c71cd 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/insane-rows-true-false-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/insane-rows-true-false-false-result.html @@ -1,7940 +1,7940 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - All Products - - All Gender - - 266,773 - - 225,627.23 - - 565,238.13 -
      - All Media - - Drink - - All Gender - - 24,597 - - 19,477.23 - - 48,836.21 -
      - All Media - - Food - - All Gender - - 191,940 - - 163,270.72 - - 409,035.59 -
      - All Media - - Baked Goods - - All Gender - - 7,870 - - 6,564.09 - - 16,455.43 -
      - All Media - - Baking Goods - - All Gender - - 20,245 - - 15,370.61 - - 38,670.41 -
      - All Media - - Baking Goods - - All Gender - - 8,357 - - 6,123.32 - - 15,446.69 -
      - All Media - - Baking Goods - - F - - 4,005 - - 2,907.70 - - 7,313.61 -
      - All Media - - Baking Goods - - M - - 4,352 - - 3,215.62 - - 8,133.08 -
      - All Media - - Jams and Jellies - - All Gender - - 11,888 - - 9,247.29 - - 23,223.72 -
      - All Media - - Jam - - All Gender - - 2,556 - - 2,132.27 - - 5,401.81 -
      - All Media - - Jelly - - All Gender - - 2,565 - - 1,830.04 - - 4,609.61 -
      - All Media - - Jelly - - F - - 1,309 - - 956.94 - - 2,414.94 -
      - All Media - - Jelly - - M - - 1,256 - - 873.10 - - 2,194.67 -
      - All Media - - Peanut Butter - - All Gender - - 2,667 - - 2,097.37 - - 5,231.08 -
      - All Media - - BBB Best - - All Gender - - 556 - - 424.38 - - 1,055.72 -
      - All Media - - BBB Best - - F - - 271 - - 201.08 - - 500.39 -
      - All Media - - BBB Best - - M - - 285 - - 223.30 - - 555.33 -
      - All Media - - BBB Best Chunky Peanut Butter - - All Gender - - 188 - - 147.32 - - 370.36 -
      - All Media - - BBB Best Chunky Peanut Butter - - F - - 107 - - 85.81 - - 210.79 -
      - All Media - - BBB Best Chunky Peanut Butter - - M - - 81 - - 61.50 - - 159.57 -
      - All Media - - BBB Best Creamy Peanut Butter - - All Gender - - 201 - - 87.86 - - 221.10 -
      - All Media - - BBB Best Creamy Peanut Butter - - F - - 99 - - 43.35 - - 108.90 -
      - All Media - - BBB Best Creamy Peanut Butter - - M - - 102 - - 44.51 - - 112.20 -
      - All Media - - BBB Best Extra Chunky Peanut Butter - - All Gender - - 167 - - 189.21 - - 464.26 -
      - All Media - - BBB Best Extra Chunky Peanut Butter - - F - - 65 - - 71.92 - - 180.70 -
      - All Media - - BBB Best Extra Chunky Peanut Butter - - M - - 102 - - 117.29 - - 283.56 -
      - All Media - - CDR - - All Gender - - 545 - - 538.88 - - 1,326.30 -
      - All Media - - Landslide - - All Gender - - 531 - - 256.16 - - 635.29 -
      - All Media - - Plato - - All Gender - - 520 - - 447.73 - - 1,132.16 -
      - All Media - - Super - - All Gender - - 515 - - 430.21 - - 1,081.61 -
      - All Media - - Preserves - - All Gender - - 4,100 - - 3,187.61 - - 7,981.22 -
      - All Media - - Preserves - - F - - 1,946 - - 1,472.42 - - 3,717.80 -
      - All Media - - Preserves - - M - - 2,154 - - 1,715.19 - - 4,263.42 -
      - All Media - - Breakfast Foods - - All Gender - - 3,317 - - 2,756.80 - - 6,941.46 -
      - All Media - - Canned Foods - - All Gender - - 19,026 - - 15,894.53 - - 39,774.34 -
      - All Media - - Canned Anchovies - - All Gender - - 900 - - 913.88 - - 2,296.38 -
      - All Media - - Canned Clams - - All Gender - - 882 - - 759.80 - - 1,912.68 -
      - All Media - - Clams - - All Gender - - 882 - - 759.80 - - 1,912.68 -
      - All Media - - Better - - All Gender - - 189 - - 151.14 - - 398.79 -
      - All Media - - Blue Label - - All Gender - - 165 - - 112.82 - - 278.85 -
      - All Media - - Bravo - - All Gender - - 184 - - 280.70 - - 708.40 -
      - All Media - - Just Right - - All Gender - - 177 - - 161.96 - - 394.71 -
      - All Media - - Pleasant - - All Gender - - 167 - - 53.17 - - 131.93 -
      - All Media - - Canned Oysters - - All Gender - - 708 - - 571.50 - - 1,442.77 -
      - All Media - - Canned Sardines - - All Gender - - 819 - - 537.59 - - 1,357.80 -
      - All Media - - Canned Shrimp - - All Gender - - 804 - - 858.39 - - 2,146.49 -
      - All Media - - Canned Soup - - All Gender - - 8,006 - - 6,408.29 - - 15,966.10 -
      - All Media - - Canned Tuna - - All Gender - - 1,710 - - 1,288.52 - - 3,210.76 -
      - All Media - - Vegetables - - All Gender - - 5,197 - - 4,556.57 - - 11,441.36 -
      - All Media - - Canned Products - - All Gender - - 1,812 - - 1,317.13 - - 3,314.52 -
      - All Media - - Dairy - - All Gender - - 12,885 - - 12,228.85 - - 30,508.85 -
      - All Media - - Deli - - All Gender - - 12,037 - - 10,108.87 - - 25,318.93 -
      - All Media - - Meat - - All Gender - - 9,433 - - 8,215.81 - - 20,616.29 -
      - All Media - - Bologna - - All Gender - - 2,588 - - 2,340.24 - - 5,859.95 -
      - All Media - - Deli Meats - - All Gender - - 3,339 - - 2,851.18 - - 7,191.24 -
      - All Media - - Deli Meats - - F - - 1,653 - - 1,414.49 - - 3,579.34 -
      - All Media - - Deli Meats - - M - - 1,686 - - 1,436.69 - - 3,611.90 -
      - All Media - - Fresh Chicken - - All Gender - - 878 - - 842.85 - - 2,091.52 -
      - All Media - - Hot Dogs - - All Gender - - 2,628 - - 2,181.55 - - 5,473.58 -
      - All Media - - Side Dishes - - All Gender - - 2,604 - - 1,893.06 - - 4,702.64 -
      - All Media - - Eggs - - All Gender - - 4,132 - - 3,684.90 - - 9,200.76 -
      - All Media - - Frozen Foods - - All Gender - - 26,655 - - 22,030.66 - - 55,207.50 -
      - All Media - - Meat - - All Gender - - 1,714 - - 1,465.42 - - 3,669.89 -
      - All Media - - Produce - - All Gender - - 37,792 - - 32,831.33 - - 82,248.42 -
      - All Media - - Seafood - - All Gender - - 1,764 - - 1,520.70 - - 3,809.14 -
      - All Media - - Snack Foods - - All Gender - - 30,545 - - 26,963.34 - - 67,609.82 -
      - All Media - - Snacks - - All Gender - - 6,884 - - 5,827.58 - - 14,550.05 -
      - All Media - - Starchy Foods - - All Gender - - 5,262 - - 4,705.91 - - 11,756.07 -
      - All Media - - Non-Consumable - - All Gender - - 50,236 - - 42,879.28 - - 107,366.33 -
      - All Media - - Carousel - - All Gender - - 841 - - 595.97 - - 1,500.11 -
      - All Media - - Checkout - - All Gender - - 1,779 - - 1,525.04 - - 3,767.71 -
      - All Media - - Health and Hygiene - - All Gender - - 16,284 - - 12,972.99 - - 32,571.86 -
      - All Media - - Household - - All Gender - - 27,038 - - 24,170.73 - - 60,469.89 -
      - All Media - - Periodicals - - All Gender - - 4,294 - - 3,614.55 - - 9,056.76 -
      - Bulk Mail - - All Products - - All Gender - - 4,320 - - 3,740.95 - - 9,349.07 -
      - Cash Register Handout - - All Products - - All Gender - - 6,697 - - 5,715.67 - - 14,321.33 -
      - Daily Paper - - All Products - - All Gender - - 7,738 - - 6,559.23 - - 16,479.81 -
      - Daily Paper, Radio - - All Products - - All Gender - - 6,891 - - 5,668.77 - - 14,169.42 -
      - Daily Paper, Radio, TV - - All Products - - All Gender - - 9,513 - - 8,055.22 - - 20,173.97 -
      - In-Store Coupon - - All Products - - All Gender - - 3,798 - - 3,263.11 - - 8,162.46 -
      - In-Store Coupon - - Drink - - All Gender - - 345 - - 282.44 - - 708.38 -
      - In-Store Coupon - - Food - - All Gender - - 2,737 - - 2,345.57 - - 5,889.34 -
      - In-Store Coupon - - Baked Goods - - All Gender - - 131 - - 114.11 - - 279.11 -
      - In-Store Coupon - - Baking Goods - - All Gender - - 308 - - 252.88 - - 632.01 -
      - In-Store Coupon - - Baking Goods - - All Gender - - 146 - - 103.30 - - 261.44 -
      - In-Store Coupon - - Jams and Jellies - - All Gender - - 162 - - 149.58 - - 370.57 -
      - In-Store Coupon - - Jam - - All Gender - - 55 - - 58.16 - - 141.19 -
      - In-Store Coupon - - Jelly - - All Gender - - 32 - - 23.96 - - 62.12 -
      - In-Store Coupon - - Peanut Butter - - All Gender - - 22 - - 19.54 - - 48.72 -
      - In-Store Coupon - - BBB Best - - All Gender - - 7 - - 6.72 - - 16.10 -
      - In-Store Coupon - - CDR - - All Gender - - 10 - - 9.81 - - 24.32 -
      - In-Store Coupon - - Landslide - - All Gender - -   - -   - -   -
      - In-Store Coupon - - Plato - - All Gender - - 3 - - 2.32 - - 6.32 -
      - In-Store Coupon - - Super - - All Gender - - 2 - - .69 - - 1.98 -
      - In-Store Coupon - - Preserves - - All Gender - - 53 - - 47.92 - - 118.54 -
      - In-Store Coupon - - Breakfast Foods - - All Gender - - 59 - - 49.22 - - 125.19 -
      - In-Store Coupon - - Breakfast Foods - - F - - 33 - - 22.88 - - 54.84 -
      - In-Store Coupon - - Breakfast Foods - - M - - 26 - - 26.34 - - 70.35 -
      - In-Store Coupon - - Canned Foods - - All Gender - - 245 - - 200.61 - - 506.67 -
      - In-Store Coupon - - Canned Products - - All Gender - - 15 - - 9.58 - - 26.17 -
      - In-Store Coupon - - Dairy - - All Gender - - 166 - - 153.42 - - 372.01 -
      - In-Store Coupon - - Deli - - All Gender - - 180 - - 163.58 - - 392.68 -
      - In-Store Coupon - - Eggs - - All Gender - - 56 - - 42.51 - - 108.90 -
      - In-Store Coupon - - Frozen Foods - - All Gender - - 374 - - 301.63 - - 773.52 -
      - In-Store Coupon - - Meat - - All Gender - - 31 - - 23.91 - - 70.35 -
      - In-Store Coupon - - Produce - - All Gender - - 563 - - 499.63 - - 1,257.05 -
      - In-Store Coupon - - Seafood - - All Gender - - 34 - - 30.06 - - 76.09 -
      - In-Store Coupon - - Snack Foods - - All Gender - - 439 - - 390.35 - - 989.13 -
      - In-Store Coupon - - Snacks - - All Gender - - 78 - - 63.77 - - 153.02 -
      - In-Store Coupon - - Starchy Foods - - All Gender - - 58 - - 50.30 - - 127.44 -
      - In-Store Coupon - - Non-Consumable - - All Gender - - 716 - - 635.10 - - 1,564.74 -
      - In-Store Coupon - - Carousel - - All Gender - - 17 - - 8.77 - - 24.18 -
      - In-Store Coupon - - Checkout - - All Gender - - 23 - - 15.20 - - 40.19 -
      - In-Store Coupon - - Health and Hygiene - - All Gender - - 251 - - 193.53 - - 477.21 -
      - In-Store Coupon - - Household - - All Gender - - 374 - - 375.66 - - 916.97 -
      - In-Store Coupon - - Periodicals - - All Gender - - 51 - - 41.94 - - 106.19 -
      - No Media - - All Products - - All Gender - - 195,448 - - 165,214.85 - - 414,026.92 -
      - No Media - - Drink - - All Gender - - 17,896 - - 14,211.41 - - 35,681.85 -
      - No Media - - Food - - All Gender - - 140,577 - - 119,469.36 - - 299,356.11 -
      - No Media - - Baked Goods - - All Gender - - 5,753 - - 4,775.86 - - 11,972.46 -
      - No Media - - Baking Goods - - All Gender - - 14,849 - - 11,226.15 - - 28,312.78 -
      - No Media - - Baking Goods - - All Gender - - 5,979 - - 4,347.34 - - 11,002.73 -
      - No Media - - Jams and Jellies - - All Gender - - 8,870 - - 6,878.81 - - 17,310.05 -
      - No Media - - Jam - - All Gender - - 1,883 - - 1,554.13 - - 3,965.74 -
      - No Media - - Jelly - - All Gender - - 1,936 - - 1,394.32 - - 3,504.71 -
      - No Media - - Peanut Butter - - All Gender - - 1,984 - - 1,534.19 - - 3,828.01 -
      - No Media - - BBB Best - - All Gender - - 406 - - 293.97 - - 735.29 -
      - No Media - - CDR - - All Gender - - 411 - - 401.88 - - 998.12 -
      - No Media - - Landslide - - All Gender - - 401 - - 195.51 - - 478.44 -
      - No Media - - Plato - - All Gender - - 384 - - 331.26 - - 832.92 -
      - No Media - - Super - - All Gender - - 382 - - 311.57 - - 783.24 -
      - No Media - - Preserves - - All Gender - - 3,067 - - 2,396.16 - - 6,011.59 -
      - No Media - - Breakfast Foods - - All Gender - - 2,418 - - 1,996.45 - - 5,016.10 -
      - No Media - - Canned Foods - - All Gender - - 13,861 - - 11,647.47 - - 29,102.79 -
      - No Media - - Canned Products - - All Gender - - 1,344 - - 960.82 - - 2,424.98 -
      - No Media - - Dairy - - All Gender - - 9,510 - - 8,981.13 - - 22,454.02 -
      - No Media - - Deli - - All Gender - - 8,695 - - 7,353.56 - - 18,410.26 -
      - No Media - - Eggs - - All Gender - - 2,976 - - 2,640.47 - - 6,606.25 -
      - No Media - - Frozen Foods - - All Gender - - 19,450 - - 16,127.24 - - 40,411.08 -
      - No Media - - Meat - - All Gender - - 1,236 - - 1,068.07 - - 2,646.00 -
      - No Media - - Produce - - All Gender - - 27,637 - - 24,036.36 - - 60,203.58 -
      - No Media - - Seafood - - All Gender - - 1,292 - - 1,114.69 - - 2,774.43 -
      - No Media - - Snack Foods - - All Gender - - 22,525 - - 19,800.82 - - 49,680.71 -
      - No Media - - Snacks - - All Gender - - 5,100 - - 4,264.55 - - 10,690.26 -
      - No Media - - Starchy Foods - - All Gender - - 3,931 - - 3,475.74 - - 8,650.41 -
      - No Media - - Non-Consumable - - All Gender - - 36,975 - - 31,534.08 - - 78,988.96 -
      - No Media - - Carousel - - All Gender - - 584 - - 419.65 - - 1,050.75 -
      - No Media - - Checkout - - All Gender - - 1,305 - - 1,113.97 - - 2,768.66 -
      - No Media - - Health and Hygiene - - All Gender - - 11,845 - - 9,413.25 - - 23,621.12 -
      - No Media - - Household - - All Gender - - 20,091 - - 17,929.20 - - 44,881.13 -
      - No Media - - Periodicals - - All Gender - - 3,150 - - 2,658.00 - - 6,667.30 -
      - Product Attachment - - All Products - - All Gender - - 7,544 - - 6,306.24 - - 15,898.25 -
      - Product Attachment - - Drink - - All Gender - - 713 - - 555.05 - - 1,403.65 -
      - Product Attachment - - Food - - All Gender - - 5,441 - - 4,571.71 - - 11,525.25 -
      - Product Attachment - - Baked Goods - - All Gender - - 213 - - 175.69 - - 445.60 -
      - Product Attachment - - Baking Goods - - All Gender - - 547 - - 410.31 - - 1,032.59 -
      - Product Attachment - - Baking Goods - - All Gender - - 258 - - 191.48 - - 470.58 -
      - Product Attachment - - Jams and Jellies - - All Gender - - 289 - - 218.83 - - 562.01 -
      - Product Attachment - - Jam - - All Gender - - 66 - - 48.03 - - 128.68 -
      - Product Attachment - - Jelly - - All Gender - - 45 - - 34.12 - - 90.62 -
      - Product Attachment - - Peanut Butter - - All Gender - - 63 - - 47.71 - - 122.31 -
      - Product Attachment - - BBB Best - - All Gender - - 15 - - 14.53 - - 38.46 -
      - Product Attachment - - CDR - - All Gender - - 13 - - 11.94 - - 30.57 -
      - Product Attachment - - Landslide - - All Gender - - 12 - - 5.32 - - 14.28 -
      - Product Attachment - - Plato - - All Gender - - 9 - - 7.16 - - 17.43 -
      - Product Attachment - - Super - - All Gender - - 14 - - 8.75 - - 21.57 -
      - Product Attachment - - Preserves - - All Gender - - 115 - - 88.98 - - 220.40 -
      - Product Attachment - - Breakfast Foods - - All Gender - - 103 - - 87.35 - - 220.75 -
      - Product Attachment - - Canned Foods - - All Gender - - 564 - - 463.28 - - 1,154.91 -
      - Product Attachment - - Canned Products - - All Gender - - 60 - - 51.61 - - 124.24 -
      - Product Attachment - - Dairy - - All Gender - - 355 - - 339.81 - - 849.78 -
      - Product Attachment - - Deli - - All Gender - - 324 - - 243.64 - - 618.23 -
      - Product Attachment - - Eggs - - All Gender - - 118 - - 97.43 - - 241.21 -
      - Product Attachment - - Frozen Foods - - All Gender - - 812 - - 665.48 - - 1,692.11 -
      - Product Attachment - - Meat - - All Gender - - 54 - - 51.36 - - 127.83 -
      - Product Attachment - - Produce - - All Gender - - 1,069 - - 909.24 - - 2,287.61 -
      - Product Attachment - - Seafood - - All Gender - - 45 - - 36.98 - - 100.61 -
      - Product Attachment - - Snack Foods - - All Gender - - 819 - - 726.73 - - 1,847.28 -
      - Product Attachment - - Snacks - - All Gender - - 209 - - 186.22 - - 450.03 -
      - Product Attachment - - Starchy Foods - - All Gender - - 149 - - 126.59 - - 332.47 -
      - Product Attachment - - Non-Consumable - - All Gender - - 1,390 - - 1,179.48 - - 2,969.35 -
      - Product Attachment - - Carousel - - All Gender - - 14 - - 7.99 - - 21.21 -
      - Product Attachment - - Checkout - - All Gender - - 48 - - 40.45 - - 100.61 -
      - Product Attachment - - Health and Hygiene - - All Gender - - 440 - - 356.54 - - 901.73 -
      - Product Attachment - - Household - - All Gender - - 777 - - 690.03 - - 1,737.96 -
      - Product Attachment - - Periodicals - - All Gender - - 111 - - 84.48 - - 207.84 -
      - Radio - - All Products - - All Gender - - 2,454 - - 2,087.51 - - 5,213.61 -
      - Radio - - Drink - - All Gender - - 226 - - 182.85 - - 443.68 -
      - Radio - - Food - - All Gender - - 1,733 - - 1,485.25 - - 3,727.36 -
      - Radio - - Baked Goods - - All Gender - - 83 - - 76.51 - - 186.20 -
      - Radio - - Baking Goods - - All Gender - - 157 - - 109.10 - - 274.90 -
      - Radio - - Baking Goods - - All Gender - - 63 - - 45.02 - - 110.43 -
      - Radio - - Jams and Jellies - - All Gender - - 94 - - 64.08 - - 164.47 -
      - Radio - - Jam - - All Gender - - 15 - - 10.42 - - 26.94 -
      - Radio - - Jelly - - All Gender - - 24 - - 14.54 - - 37.49 -
      - Radio - - Peanut Butter - - All Gender - - 19 - - 16.85 - - 41.82 -
      - Radio - - BBB Best - - All Gender - - 10 - - 10.58 - - 24.44 -
      - Radio - - CDR - - All Gender - -   - -   - -   -
      - Radio - - Landslide - - All Gender - -   - -   - -   -
      - Radio - - Plato - - All Gender - - 4 - - 3.77 - - 9.80 -
      - Radio - - Super - - All Gender - - 5 - - 2.50 - - 7.58 -
      - Radio - - Preserves - - All Gender - - 36 - - 22.28 - - 58.22 -
      - Radio - - Breakfast Foods - - All Gender - - 25 - - 18.78 - - 50.22 -
      - Radio - - Canned Foods - - All Gender - - 158 - - 124.79 - - 307.55 -
      - Radio - - Canned Products - - All Gender - - 22 - - 17.29 - - 43.42 -
      - Radio - - Dairy - - All Gender - - 112 - - 92.12 - - 216.79 -
      - Radio - - Deli - - All Gender - - 129 - - 119.14 - - 307.25 -
      - Radio - - Eggs - - All Gender - - 25 - - 29.97 - - 71.15 -
      - Radio - - Frozen Foods - - All Gender - - 253 - - 202.71 - - 507.45 -
      - Radio - - Meat - - All Gender - - 12 - - 11.53 - - 32.85 -
      - Radio - - Produce - - All Gender - - 336 - - 292.05 - - 738.20 -
      - Radio - - Seafood - - All Gender - - 15 - - 13.28 - - 35.58 -
      - Radio - - Snack Foods - - All Gender - - 290 - - 270.59 - - 674.73 -
      - Radio - - Snacks - - All Gender - - 60 - - 55.67 - - 144.58 -
      - Radio - - Starchy Foods - - All Gender - - 56 - - 51.72 - - 136.49 -
      - Radio - - Non-Consumable - - All Gender - - 495 - - 419.41 - - 1,042.57 -
      - Radio - - Carousel - - All Gender - - 15 - - 11.15 - - 26.85 -
      - Radio - - Checkout - - All Gender - - 21 - - 17.00 - - 42.74 -
      - Radio - - Health and Hygiene - - All Gender - - 145 - - 114.84 - - 289.80 -
      - Radio - - Household - - All Gender - - 258 - - 233.31 - - 575.07 -
      - Radio - - Periodicals - - All Gender - - 56 - - 43.12 - - 108.11 -
      - Street Handout - - All Products - - All Gender - - 5,753 - - 4,856.54 - - 12,192.90 -
      - Street Handout - - Drink - - All Gender - - 512 - - 372.68 - - 943.42 -
      - Street Handout - - Food - - All Gender - - 4,239 - - 3,650.32 - - 9,151.65 -
      - Street Handout - - Baked Goods - - All Gender - - 160 - - 120.12 - - 301.62 -
      - Street Handout - - Baking Goods - - All Gender - - 498 - - 373.67 - - 923.22 -
      - Street Handout - - Baking Goods - - All Gender - - 200 - - 144.16 - - 357.82 -
      - Street Handout - - Jams and Jellies - - All Gender - - 298 - - 229.51 - - 565.40 -
      - Street Handout - - Jam - - All Gender - - 53 - - 44.30 - - 112.95 -
      - Street Handout - - Jelly - - All Gender - - 92 - - 63.14 - - 155.59 -
      - Street Handout - - Peanut Butter - - All Gender - - 51 - - 51.06 - - 118.90 -
      - Street Handout - - BBB Best - - All Gender - - 11 - - 10.85 - - 25.72 -
      - Street Handout - - CDR - - All Gender - - 8 - - 9.06 - - 19.73 -
      - Street Handout - - Landslide - - All Gender - - 11 - - 6.90 - - 15.54 -
      - Street Handout - - Plato - - All Gender - - 9 - - 8.47 - - 20.89 -
      - Street Handout - - Super - - All Gender - - 12 - - 15.78 - - 37.02 -
      - Street Handout - - Preserves - - All Gender - - 102 - - 71.02 - - 177.96 -
      - Street Handout - - Breakfast Foods - - All Gender - - 81 - - 74.32 - - 192.90 -
      - Street Handout - - Canned Foods - - All Gender - - 459 - - 413.21 - - 1,021.86 -
      - Street Handout - - Canned Products - - All Gender - - 30 - - 19.43 - - 45.68 -
      - Street Handout - - Dairy - - All Gender - - 301 - - 285.98 - - 718.61 -
      - Street Handout - - Deli - - All Gender - - 305 - - 253.54 - - 638.30 -
      - Street Handout - - Eggs - - All Gender - - 66 - - 59.15 - - 156.82 -
      - Street Handout - - Frozen Foods - - All Gender - - 612 - - 520.12 - - 1,313.71 -
      - Street Handout - - Meat - - All Gender - - 37 - - 29.82 - - 78.24 -
      - Street Handout - - Produce - - All Gender - - 745 - - 662.39 - - 1,639.94 -
      - Street Handout - - Seafood - - All Gender - - 37 - - 30.12 - - 72.77 -
      - Street Handout - - Snack Foods - - All Gender - - 675 - - 600.23 - - 1,515.68 -
      - Street Handout - - Snacks - - All Gender - - 144 - - 128.79 - - 321.16 -
      - Street Handout - - Starchy Foods - - All Gender - - 89 - - 79.43 - - 211.14 -
      - Street Handout - - Non-Consumable - - All Gender - - 1,002 - - 833.53 - - 2,097.83 -
      - Street Handout - - Carousel - - All Gender - - 17 - - 13.53 - - 30.98 -
      - Street Handout - - Checkout - - All Gender - - 45 - - 34.77 - - 85.38 -
      - Street Handout - - Health and Hygiene - - All Gender - - 402 - - 318.03 - - 802.92 -
      - Street Handout - - Household - - All Gender - - 501 - - 436.41 - - 1,105.38 -
      - Street Handout - - Periodicals - - All Gender - - 37 - - 30.80 - - 73.17 -
      - Sunday Paper - - All Products - - All Gender - - 4,339 - - 3,673.86 - - 9,092.89 -
      - Sunday Paper - - Drink - - All Gender - - 430 - - 345.53 - - 856.73 -
      - Sunday Paper - - Food - - All Gender - - 3,106 - - 2,646.47 - - 6,559.46 -
      - Sunday Paper - - Baked Goods - - All Gender - - 140 - - 110.79 - - 282.55 -
      - Sunday Paper - - Baking Goods - - All Gender - - 338 - - 239.76 - - 603.86 -
      - Sunday Paper - - Baking Goods - - All Gender - - 170 - - 118.05 - - 298.79 -
      - Sunday Paper - - Jams and Jellies - - All Gender - - 168 - - 121.71 - - 305.07 -
      - Sunday Paper - - Jam - - All Gender - - 24 - - 22.35 - - 54.83 -
      - Sunday Paper - - Jelly - - All Gender - - 27 - - 18.20 - - 47.12 -
      - Sunday Paper - - Peanut Butter - - All Gender - - 51 - - 37.67 - - 96.67 -
      - Sunday Paper - - BBB Best - - All Gender - - 10 - - 6.08 - - 16.22 -
      - Sunday Paper - - CDR - - All Gender - - 10 - - 10.47 - - 26.50 -
      - Sunday Paper - - Landslide - - All Gender - - 15 - - 6.20 - - 16.31 -
      - Sunday Paper - - Plato - - All Gender - - 16 - - 14.93 - - 37.64 -
      - Sunday Paper - - Super - - All Gender - -   - -   - -   -
      - Sunday Paper - - Preserves - - All Gender - - 66 - - 43.49 - - 106.45 -
      - Sunday Paper - - Breakfast Foods - - All Gender - - 55 - - 49.80 - - 120.23 -
      - Sunday Paper - - Canned Foods - - All Gender - - 283 - - 249.46 - - 605.11 -
      - Sunday Paper - - Canned Products - - All Gender - - 34 - - 29.65 - - 72.18 -
      - Sunday Paper - - Dairy - - All Gender - - 200 - - 201.94 - - 497.91 -
      - Sunday Paper - - Deli - - All Gender - - 228 - - 188.37 - - 467.53 -
      - Sunday Paper - - Eggs - - All Gender - - 54 - - 47.68 - - 118.44 -
      - Sunday Paper - - Frozen Foods - - All Gender - - 425 - - 330.81 - - 839.15 -
      - Sunday Paper - - Meat - - All Gender - - 18 - - 19.85 - - 52.20 -
      - Sunday Paper - - Produce - - All Gender - - 603 - - 520.95 - - 1,274.70 -
      - Sunday Paper - - Seafood - - All Gender - - 27 - - 26.82 - - 69.49 -
      - Sunday Paper - - Snack Foods - - All Gender - - 469 - - 413.18 - - 1,027.98 -
      - Sunday Paper - - Snacks - - All Gender - - 123 - - 108.50 - - 261.38 -
      - Sunday Paper - - Starchy Foods - - All Gender - - 109 - - 108.91 - - 266.75 -
      - Sunday Paper - - Non-Consumable - - All Gender - - 803 - - 681.86 - - 1,676.70 -
      - Sunday Paper - - Carousel - - All Gender - - 7 - - 6.70 - - 14.68 -
      - Sunday Paper - - Checkout - - All Gender - - 17 - - 13.09 - - 30.89 -
      - Sunday Paper - - Health and Hygiene - - All Gender - - 278 - - 227.06 - - 565.99 -
      - Sunday Paper - - Household - - All Gender - - 420 - - 371.58 - - 911.69 -
      - Sunday Paper - - Periodicals - - All Gender - - 81 - - 63.43 - - 153.45 -
      - Sunday Paper, Radio - - All Products - - All Gender - - 5,945 - - 5,027.31 - - 12,551.96 -
      - Sunday Paper, Radio - - Drink - - All Gender - - 591 - - 454.03 - - 1,129.94 -
      - Sunday Paper, Radio - - Food - - All Gender - - 4,239 - - 3,612.38 - - 9,033.23 -
      - Sunday Paper, Radio - - Baked Goods - - All Gender - - 152 - - 109.11 - - 274.39 -
      - Sunday Paper, Radio - - Baking Goods - - All Gender - - 482 - - 367.13 - - 913.84 -
      - Sunday Paper, Radio - - Baking Goods - - All Gender - - 206 - - 152.72 - - 381.59 -
      - Sunday Paper, Radio - - Jams and Jellies - - All Gender - - 276 - - 214.41 - - 532.25 -
      - Sunday Paper, Radio - - Jam - - All Gender - - 52 - - 52.39 - - 126.62 -
      - Sunday Paper, Radio - - Jelly - - All Gender - - 74 - - 53.93 - - 135.03 -
      - Sunday Paper, Radio - - Peanut Butter - - All Gender - - 64 - - 50.10 - - 126.71 -
      - Sunday Paper, Radio - - BBB Best - - All Gender - - 14 - - 11.58 - - 27.40 -
      - Sunday Paper, Radio - - CDR - - All Gender - - 17 - - 14.68 - - 41.25 -
      - Sunday Paper, Radio - - Landslide - - All Gender - - 14 - - 6.62 - - 17.04 -
      - Sunday Paper, Radio - - Plato - - All Gender - - 7 - - 6.91 - - 17.15 -
      - Sunday Paper, Radio - - Super - - All Gender - - 12 - - 10.31 - - 23.87 -
      - Sunday Paper, Radio - - Preserves - - All Gender - - 86 - - 57.99 - - 143.89 -
      - Sunday Paper, Radio - - Breakfast Foods - - All Gender - - 80 - - 62.80 - - 154.04 -
      - Sunday Paper, Radio - - Canned Foods - - All Gender - - 456 - - 361.79 - - 914.81 -
      - Sunday Paper, Radio - - Canned Products - - All Gender - - 45 - - 39.72 - - 95.88 -
      - Sunday Paper, Radio - - Dairy - - All Gender - - 283 - - 296.91 - - 722.75 -
      - Sunday Paper, Radio - - Deli - - All Gender - - 252 - - 190.32 - - 479.59 -
      - Sunday Paper, Radio - - Eggs - - All Gender - - 114 - - 104.65 - - 256.15 -
      - Sunday Paper, Radio - - Frozen Foods - - All Gender - - 599 - - 490.33 - - 1,222.54 -
      - Sunday Paper, Radio - - Meat - - All Gender - - 40 - - 31.66 - - 84.76 -
      - Sunday Paper, Radio - - Produce - - All Gender - - 858 - - 752.62 - - 1,886.01 -
      - Sunday Paper, Radio - - Seafood - - All Gender - - 27 - - 20.66 - - 50.39 -
      - Sunday Paper, Radio - - Snack Foods - - All Gender - - 596 - - 555.70 - - 1,402.21 -
      - Sunday Paper, Radio - - Snacks - - All Gender - - 147 - - 120.43 - - 304.18 -
      - Sunday Paper, Radio - - Starchy Foods - - All Gender - - 108 - - 108.55 - - 271.69 -
      - Sunday Paper, Radio - - Non-Consumable - - All Gender - - 1,115 - - 960.90 - - 2,388.79 -
      - Sunday Paper, Radio - - Carousel - - All Gender - - 18 - - 10.99 - - 26.94 -
      - Sunday Paper, Radio - - Checkout - - All Gender - - 26 - - 24.68 - - 62.14 -
      - Sunday Paper, Radio - - Health and Hygiene - - All Gender - - 378 - - 309.37 - - 771.48 -
      - Sunday Paper, Radio - - Household - - All Gender - - 585 - - 516.99 - - 1,276.16 -
      - Sunday Paper, Radio - - Periodicals - - All Gender - - 108 - - 98.86 - - 252.07 -
      - Sunday Paper, Radio, TV - - All Products - - All Gender - - 2,726 - - 2,341.58 - - 5,819.33 -
      - Sunday Paper, Radio, TV - - Drink - - All Gender - - 225 - - 163.09 - - 403.51 -
      - Sunday Paper, Radio, TV - - Food - - All Gender - - 2,021 - - 1,762.18 - - 4,377.85 -
      - Sunday Paper, Radio, TV - - Baked Goods - - All Gender - - 67 - - 66.17 - - 163.29 -
      - Sunday Paper, Radio, TV - - Baking Goods - - All Gender - - 228 - - 182.98 - - 455.90 -
      - Sunday Paper, Radio, TV - - Baking Goods - - All Gender - - 90 - - 73.09 - - 176.63 -
      - Sunday Paper, Radio, TV - - Jams and Jellies - - All Gender - - 138 - - 109.90 - - 279.27 -
      - Sunday Paper, Radio, TV - - Jam - - All Gender - - 37 - - 31.30 - - 78.56 -
      - Sunday Paper, Radio, TV - - Jelly - - All Gender - - 27 - - 16.18 - - 39.92 -
      - Sunday Paper, Radio, TV - - Peanut Butter - - All Gender - - 30 - - 24.01 - - 64.19 -
      - Sunday Paper, Radio, TV - - BBB Best - - All Gender - - 11 - - 9.78 - - 23.86 -
      - Sunday Paper, Radio, TV - - CDR - - All Gender - -   - -   - -   -
      - Sunday Paper, Radio, TV - - Landslide - - All Gender - - 4 - - 2.39 - - 5.68 -
      - Sunday Paper, Radio, TV - - Plato - - All Gender - - 5 - - 3.85 - - 11.60 -
      - Sunday Paper, Radio, TV - - Super - - All Gender - - 10 - - 7.99 - - 23.05 -
      - Sunday Paper, Radio, TV - - Preserves - - All Gender - - 44 - - 38.41 - - 96.60 -
      - Sunday Paper, Radio, TV - - Breakfast Foods - - All Gender - - 38 - - 32.76 - - 89.85 -
      - Sunday Paper, Radio, TV - - Canned Foods - - All Gender - - 180 - - 138.77 - - 340.04 -
      - Sunday Paper, Radio, TV - - Canned Products - - All Gender - - 14 - - 12.00 - - 28.28 -
      - Sunday Paper, Radio, TV - - Dairy - - All Gender - - 121 - - 125.32 - - 305.43 -
      - Sunday Paper, Radio, TV - - Deli - - All Gender - - 131 - - 98.93 - - 245.42 -
      - Sunday Paper, Radio, TV - - Eggs - - All Gender - - 39 - - 39.57 - - 91.99 -
      - Sunday Paper, Radio, TV - - Frozen Foods - - All Gender - - 279 - - 207.59 - - 514.95 -
      - Sunday Paper, Radio, TV - - Meat - - All Gender - - 12 - - 11.77 - - 30.23 -
      - Sunday Paper, Radio, TV - - Produce - - All Gender - - 411 - - 382.14 - - 943.93 -
      - Sunday Paper, Radio, TV - - Seafood - - All Gender - - 31 - - 28.07 - - 69.82 -
      - Sunday Paper, Radio, TV - - Snack Foods - - All Gender - - 346 - - 318.26 - - 798.50 -
      - Sunday Paper, Radio, TV - - Snacks - - All Gender - - 75 - - 65.49 - - 174.02 -
      - Sunday Paper, Radio, TV - - Starchy Foods - - All Gender - - 49 - - 52.37 - - 126.20 -
      - Sunday Paper, Radio, TV - - Non-Consumable - - All Gender - - 480 - - 416.30 - - 1,037.97 -
      - Sunday Paper, Radio, TV - - Carousel - - All Gender - - 21 - - 11.63 - - 27.92 -
      - Sunday Paper, Radio, TV - - Checkout - - All Gender - - 10 - - 8.12 - - 19.80 -
      - Sunday Paper, Radio, TV - - Health and Hygiene - - All Gender - - 138 - - 110.35 - - 276.31 -
      - Sunday Paper, Radio, TV - - Household - - All Gender - - 262 - - 244.90 - - 608.52 -
      - Sunday Paper, Radio, TV - - Periodicals - - All Gender - - 49 - - 41.30 - - 105.42 -
      - TV - - All Products - - All Gender - - 3,607 - - 3,116.40 - - 7,786.21 -
      - TV - - Drink - - All Gender - - 332 - - 283.18 - - 721.07 -
      - TV - - Food - - All Gender - - 2,563 - - 2,238.13 - - 5,573.27 -
      - TV - - Baked Goods - - All Gender - - 114 - - 103.40 - - 262.97 -
      - TV - - Baking Goods - - All Gender - - 237 - - 185.55 - - 464.23 -
      - TV - - Baking Goods - - All Gender - - 95 - - 74.29 - - 190.59 -
      - TV - - Jams and Jellies - - All Gender - - 142 - - 111.25 - - 273.64 -
      - TV - - Jam - - All Gender - - 38 - - 32.28 - - 77.58 -
      - TV - - Jelly - - All Gender - - 35 - - 24.64 - - 63.38 -
      - TV - - Peanut Butter - - All Gender - - 31 - - 21.83 - - 56.80 -
      - TV - - BBB Best - - All Gender - -   - -   - -   -
      - TV - - CDR - - All Gender - - 11 - - 9.78 - - 27.19 -
      - TV - - Landslide - - All Gender - - 7 - - 2.61 - - 7.12 -
      - TV - - Plato - - All Gender - - 6 - - 4.95 - - 12.13 -
      - TV - - Super - - All Gender - - 7 - - 4.48 - - 10.36 -
      - TV - - Preserves - - All Gender - - 38 - - 32.51 - - 75.88 -
      - TV - - Breakfast Foods - - All Gender - - 36 - - 30.11 - - 79.89 -
      - TV - - Canned Foods - - All Gender - - 240 - - 200.00 - - 519.91 -
      - TV - - Canned Products - - All Gender - - 26 - - 15.00 - - 38.65 -
      - TV - - Dairy - - All Gender - - 179 - - 183.73 - - 458.87 -
      - TV - - Deli - - All Gender - - 155 - - 139.76 - - 342.51 -
      - TV - - Eggs - - All Gender - - 42 - - 32.74 - - 80.93 -
      - TV - - Frozen Foods - - All Gender - - 352 - - 300.42 - - 738.40 -
      - TV - - Meat - - All Gender - - 22 - - 19.76 - - 49.27 -
      - TV - - Produce - - All Gender - - 543 - - 456.53 - - 1,145.45 -
      - TV - - Seafood - - All Gender - - 34 - - 30.71 - - 75.47 -
      - TV - - Snack Foods - - All Gender - - 401 - - 377.01 - - 927.50 -
      - TV - - Snacks - - All Gender - - 99 - - 92.80 - - 220.54 -
      - TV - - Starchy Foods - - All Gender - - 83 - - 70.61 - - 168.68 -
      - TV - - Non-Consumable - - All Gender - - 712 - - 595.08 - - 1,491.87 -
      - TV - - Carousel - - All Gender - - 4 - - 3.13 - - 9.20 -
      - TV - - Checkout - - All Gender - - 34 - - 34.12 - - 86.21 -
      - TV - - Health and Hygiene - - All Gender - - 249 - - 196.08 - - 486.46 -
      - TV - - Household - - All Gender - - 361 - - 316.09 - - 795.40 -
      - TV - - Periodicals - - All Gender - - 64 - - 45.67 - - 114.60 -
      +   + + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + All Products + + All Gender + + 266,773 + + 225,627.23 + + 565,238.13 +
      + All Media + + Drink + + All Gender + + 24,597 + + 19,477.23 + + 48,836.21 +
      + All Media + + Food + + All Gender + + 191,940 + + 163,270.72 + + 409,035.59 +
      + All Media + + Baked Goods + + All Gender + + 7,870 + + 6,564.09 + + 16,455.43 +
      + All Media + + Baking Goods + + All Gender + + 20,245 + + 15,370.61 + + 38,670.41 +
      + All Media + + Baking Goods + + All Gender + + 8,357 + + 6,123.32 + + 15,446.69 +
      + All Media + + Baking Goods + + F + + 4,005 + + 2,907.70 + + 7,313.61 +
      + All Media + + Baking Goods + + M + + 4,352 + + 3,215.62 + + 8,133.08 +
      + All Media + + Jams and Jellies + + All Gender + + 11,888 + + 9,247.29 + + 23,223.72 +
      + All Media + + Jam + + All Gender + + 2,556 + + 2,132.27 + + 5,401.81 +
      + All Media + + Jelly + + All Gender + + 2,565 + + 1,830.04 + + 4,609.61 +
      + All Media + + Jelly + + F + + 1,309 + + 956.94 + + 2,414.94 +
      + All Media + + Jelly + + M + + 1,256 + + 873.10 + + 2,194.67 +
      + All Media + + Peanut Butter + + All Gender + + 2,667 + + 2,097.37 + + 5,231.08 +
      + All Media + + BBB Best + + All Gender + + 556 + + 424.38 + + 1,055.72 +
      + All Media + + BBB Best + + F + + 271 + + 201.08 + + 500.39 +
      + All Media + + BBB Best + + M + + 285 + + 223.30 + + 555.33 +
      + All Media + + BBB Best Chunky Peanut Butter + + All Gender + + 188 + + 147.32 + + 370.36 +
      + All Media + + BBB Best Chunky Peanut Butter + + F + + 107 + + 85.81 + + 210.79 +
      + All Media + + BBB Best Chunky Peanut Butter + + M + + 81 + + 61.50 + + 159.57 +
      + All Media + + BBB Best Creamy Peanut Butter + + All Gender + + 201 + + 87.86 + + 221.10 +
      + All Media + + BBB Best Creamy Peanut Butter + + F + + 99 + + 43.35 + + 108.90 +
      + All Media + + BBB Best Creamy Peanut Butter + + M + + 102 + + 44.51 + + 112.20 +
      + All Media + + BBB Best Extra Chunky Peanut Butter + + All Gender + + 167 + + 189.21 + + 464.26 +
      + All Media + + BBB Best Extra Chunky Peanut Butter + + F + + 65 + + 71.92 + + 180.70 +
      + All Media + + BBB Best Extra Chunky Peanut Butter + + M + + 102 + + 117.29 + + 283.56 +
      + All Media + + CDR + + All Gender + + 545 + + 538.88 + + 1,326.30 +
      + All Media + + Landslide + + All Gender + + 531 + + 256.16 + + 635.29 +
      + All Media + + Plato + + All Gender + + 520 + + 447.73 + + 1,132.16 +
      + All Media + + Super + + All Gender + + 515 + + 430.21 + + 1,081.61 +
      + All Media + + Preserves + + All Gender + + 4,100 + + 3,187.61 + + 7,981.22 +
      + All Media + + Preserves + + F + + 1,946 + + 1,472.42 + + 3,717.80 +
      + All Media + + Preserves + + M + + 2,154 + + 1,715.19 + + 4,263.42 +
      + All Media + + Breakfast Foods + + All Gender + + 3,317 + + 2,756.80 + + 6,941.46 +
      + All Media + + Canned Foods + + All Gender + + 19,026 + + 15,894.53 + + 39,774.34 +
      + All Media + + Canned Anchovies + + All Gender + + 900 + + 913.88 + + 2,296.38 +
      + All Media + + Canned Clams + + All Gender + + 882 + + 759.80 + + 1,912.68 +
      + All Media + + Clams + + All Gender + + 882 + + 759.80 + + 1,912.68 +
      + All Media + + Better + + All Gender + + 189 + + 151.14 + + 398.79 +
      + All Media + + Blue Label + + All Gender + + 165 + + 112.82 + + 278.85 +
      + All Media + + Bravo + + All Gender + + 184 + + 280.70 + + 708.40 +
      + All Media + + Just Right + + All Gender + + 177 + + 161.96 + + 394.71 +
      + All Media + + Pleasant + + All Gender + + 167 + + 53.17 + + 131.93 +
      + All Media + + Canned Oysters + + All Gender + + 708 + + 571.50 + + 1,442.77 +
      + All Media + + Canned Sardines + + All Gender + + 819 + + 537.59 + + 1,357.80 +
      + All Media + + Canned Shrimp + + All Gender + + 804 + + 858.39 + + 2,146.49 +
      + All Media + + Canned Soup + + All Gender + + 8,006 + + 6,408.29 + + 15,966.10 +
      + All Media + + Canned Tuna + + All Gender + + 1,710 + + 1,288.52 + + 3,210.76 +
      + All Media + + Vegetables + + All Gender + + 5,197 + + 4,556.57 + + 11,441.36 +
      + All Media + + Canned Products + + All Gender + + 1,812 + + 1,317.13 + + 3,314.52 +
      + All Media + + Dairy + + All Gender + + 12,885 + + 12,228.85 + + 30,508.85 +
      + All Media + + Deli + + All Gender + + 12,037 + + 10,108.87 + + 25,318.93 +
      + All Media + + Meat + + All Gender + + 9,433 + + 8,215.81 + + 20,616.29 +
      + All Media + + Bologna + + All Gender + + 2,588 + + 2,340.24 + + 5,859.95 +
      + All Media + + Deli Meats + + All Gender + + 3,339 + + 2,851.18 + + 7,191.24 +
      + All Media + + Deli Meats + + F + + 1,653 + + 1,414.49 + + 3,579.34 +
      + All Media + + Deli Meats + + M + + 1,686 + + 1,436.69 + + 3,611.90 +
      + All Media + + Fresh Chicken + + All Gender + + 878 + + 842.85 + + 2,091.52 +
      + All Media + + Hot Dogs + + All Gender + + 2,628 + + 2,181.55 + + 5,473.58 +
      + All Media + + Side Dishes + + All Gender + + 2,604 + + 1,893.06 + + 4,702.64 +
      + All Media + + Eggs + + All Gender + + 4,132 + + 3,684.90 + + 9,200.76 +
      + All Media + + Frozen Foods + + All Gender + + 26,655 + + 22,030.66 + + 55,207.50 +
      + All Media + + Meat + + All Gender + + 1,714 + + 1,465.42 + + 3,669.89 +
      + All Media + + Produce + + All Gender + + 37,792 + + 32,831.33 + + 82,248.42 +
      + All Media + + Seafood + + All Gender + + 1,764 + + 1,520.70 + + 3,809.14 +
      + All Media + + Snack Foods + + All Gender + + 30,545 + + 26,963.34 + + 67,609.82 +
      + All Media + + Snacks + + All Gender + + 6,884 + + 5,827.58 + + 14,550.05 +
      + All Media + + Starchy Foods + + All Gender + + 5,262 + + 4,705.91 + + 11,756.07 +
      + All Media + + Non-Consumable + + All Gender + + 50,236 + + 42,879.28 + + 107,366.33 +
      + All Media + + Carousel + + All Gender + + 841 + + 595.97 + + 1,500.11 +
      + All Media + + Checkout + + All Gender + + 1,779 + + 1,525.04 + + 3,767.71 +
      + All Media + + Health and Hygiene + + All Gender + + 16,284 + + 12,972.99 + + 32,571.86 +
      + All Media + + Household + + All Gender + + 27,038 + + 24,170.73 + + 60,469.89 +
      + All Media + + Periodicals + + All Gender + + 4,294 + + 3,614.55 + + 9,056.76 +
      + Bulk Mail + + All Products + + All Gender + + 4,320 + + 3,740.95 + + 9,349.07 +
      + Cash Register Handout + + All Products + + All Gender + + 6,697 + + 5,715.67 + + 14,321.33 +
      + Daily Paper + + All Products + + All Gender + + 7,738 + + 6,559.23 + + 16,479.81 +
      + Daily Paper, Radio + + All Products + + All Gender + + 6,891 + + 5,668.77 + + 14,169.42 +
      + Daily Paper, Radio, TV + + All Products + + All Gender + + 9,513 + + 8,055.22 + + 20,173.97 +
      + In-Store Coupon + + All Products + + All Gender + + 3,798 + + 3,263.11 + + 8,162.46 +
      + In-Store Coupon + + Drink + + All Gender + + 345 + + 282.44 + + 708.38 +
      + In-Store Coupon + + Food + + All Gender + + 2,737 + + 2,345.57 + + 5,889.34 +
      + In-Store Coupon + + Baked Goods + + All Gender + + 131 + + 114.11 + + 279.11 +
      + In-Store Coupon + + Baking Goods + + All Gender + + 308 + + 252.88 + + 632.01 +
      + In-Store Coupon + + Baking Goods + + All Gender + + 146 + + 103.30 + + 261.44 +
      + In-Store Coupon + + Jams and Jellies + + All Gender + + 162 + + 149.58 + + 370.57 +
      + In-Store Coupon + + Jam + + All Gender + + 55 + + 58.16 + + 141.19 +
      + In-Store Coupon + + Jelly + + All Gender + + 32 + + 23.96 + + 62.12 +
      + In-Store Coupon + + Peanut Butter + + All Gender + + 22 + + 19.54 + + 48.72 +
      + In-Store Coupon + + BBB Best + + All Gender + + 7 + + 6.72 + + 16.10 +
      + In-Store Coupon + + CDR + + All Gender + + 10 + + 9.81 + + 24.32 +
      + In-Store Coupon + + Landslide + + All Gender + +   + +   + +   +
      + In-Store Coupon + + Plato + + All Gender + + 3 + + 2.32 + + 6.32 +
      + In-Store Coupon + + Super + + All Gender + + 2 + + .69 + + 1.98 +
      + In-Store Coupon + + Preserves + + All Gender + + 53 + + 47.92 + + 118.54 +
      + In-Store Coupon + + Breakfast Foods + + All Gender + + 59 + + 49.22 + + 125.19 +
      + In-Store Coupon + + Breakfast Foods + + F + + 33 + + 22.88 + + 54.84 +
      + In-Store Coupon + + Breakfast Foods + + M + + 26 + + 26.34 + + 70.35 +
      + In-Store Coupon + + Canned Foods + + All Gender + + 245 + + 200.61 + + 506.67 +
      + In-Store Coupon + + Canned Products + + All Gender + + 15 + + 9.58 + + 26.17 +
      + In-Store Coupon + + Dairy + + All Gender + + 166 + + 153.42 + + 372.01 +
      + In-Store Coupon + + Deli + + All Gender + + 180 + + 163.58 + + 392.68 +
      + In-Store Coupon + + Eggs + + All Gender + + 56 + + 42.51 + + 108.90 +
      + In-Store Coupon + + Frozen Foods + + All Gender + + 374 + + 301.63 + + 773.52 +
      + In-Store Coupon + + Meat + + All Gender + + 31 + + 23.91 + + 70.35 +
      + In-Store Coupon + + Produce + + All Gender + + 563 + + 499.63 + + 1,257.05 +
      + In-Store Coupon + + Seafood + + All Gender + + 34 + + 30.06 + + 76.09 +
      + In-Store Coupon + + Snack Foods + + All Gender + + 439 + + 390.35 + + 989.13 +
      + In-Store Coupon + + Snacks + + All Gender + + 78 + + 63.77 + + 153.02 +
      + In-Store Coupon + + Starchy Foods + + All Gender + + 58 + + 50.30 + + 127.44 +
      + In-Store Coupon + + Non-Consumable + + All Gender + + 716 + + 635.10 + + 1,564.74 +
      + In-Store Coupon + + Carousel + + All Gender + + 17 + + 8.77 + + 24.18 +
      + In-Store Coupon + + Checkout + + All Gender + + 23 + + 15.20 + + 40.19 +
      + In-Store Coupon + + Health and Hygiene + + All Gender + + 251 + + 193.53 + + 477.21 +
      + In-Store Coupon + + Household + + All Gender + + 374 + + 375.66 + + 916.97 +
      + In-Store Coupon + + Periodicals + + All Gender + + 51 + + 41.94 + + 106.19 +
      + No Media + + All Products + + All Gender + + 195,448 + + 165,214.85 + + 414,026.92 +
      + No Media + + Drink + + All Gender + + 17,896 + + 14,211.41 + + 35,681.85 +
      + No Media + + Food + + All Gender + + 140,577 + + 119,469.36 + + 299,356.11 +
      + No Media + + Baked Goods + + All Gender + + 5,753 + + 4,775.86 + + 11,972.46 +
      + No Media + + Baking Goods + + All Gender + + 14,849 + + 11,226.15 + + 28,312.78 +
      + No Media + + Baking Goods + + All Gender + + 5,979 + + 4,347.34 + + 11,002.73 +
      + No Media + + Jams and Jellies + + All Gender + + 8,870 + + 6,878.81 + + 17,310.05 +
      + No Media + + Jam + + All Gender + + 1,883 + + 1,554.13 + + 3,965.74 +
      + No Media + + Jelly + + All Gender + + 1,936 + + 1,394.32 + + 3,504.71 +
      + No Media + + Peanut Butter + + All Gender + + 1,984 + + 1,534.19 + + 3,828.01 +
      + No Media + + BBB Best + + All Gender + + 406 + + 293.97 + + 735.29 +
      + No Media + + CDR + + All Gender + + 411 + + 401.88 + + 998.12 +
      + No Media + + Landslide + + All Gender + + 401 + + 195.51 + + 478.44 +
      + No Media + + Plato + + All Gender + + 384 + + 331.26 + + 832.92 +
      + No Media + + Super + + All Gender + + 382 + + 311.57 + + 783.24 +
      + No Media + + Preserves + + All Gender + + 3,067 + + 2,396.16 + + 6,011.59 +
      + No Media + + Breakfast Foods + + All Gender + + 2,418 + + 1,996.45 + + 5,016.10 +
      + No Media + + Canned Foods + + All Gender + + 13,861 + + 11,647.47 + + 29,102.79 +
      + No Media + + Canned Products + + All Gender + + 1,344 + + 960.82 + + 2,424.98 +
      + No Media + + Dairy + + All Gender + + 9,510 + + 8,981.13 + + 22,454.02 +
      + No Media + + Deli + + All Gender + + 8,695 + + 7,353.56 + + 18,410.26 +
      + No Media + + Eggs + + All Gender + + 2,976 + + 2,640.47 + + 6,606.25 +
      + No Media + + Frozen Foods + + All Gender + + 19,450 + + 16,127.24 + + 40,411.08 +
      + No Media + + Meat + + All Gender + + 1,236 + + 1,068.07 + + 2,646.00 +
      + No Media + + Produce + + All Gender + + 27,637 + + 24,036.36 + + 60,203.58 +
      + No Media + + Seafood + + All Gender + + 1,292 + + 1,114.69 + + 2,774.43 +
      + No Media + + Snack Foods + + All Gender + + 22,525 + + 19,800.82 + + 49,680.71 +
      + No Media + + Snacks + + All Gender + + 5,100 + + 4,264.55 + + 10,690.26 +
      + No Media + + Starchy Foods + + All Gender + + 3,931 + + 3,475.74 + + 8,650.41 +
      + No Media + + Non-Consumable + + All Gender + + 36,975 + + 31,534.08 + + 78,988.96 +
      + No Media + + Carousel + + All Gender + + 584 + + 419.65 + + 1,050.75 +
      + No Media + + Checkout + + All Gender + + 1,305 + + 1,113.97 + + 2,768.66 +
      + No Media + + Health and Hygiene + + All Gender + + 11,845 + + 9,413.25 + + 23,621.12 +
      + No Media + + Household + + All Gender + + 20,091 + + 17,929.20 + + 44,881.13 +
      + No Media + + Periodicals + + All Gender + + 3,150 + + 2,658.00 + + 6,667.30 +
      + Product Attachment + + All Products + + All Gender + + 7,544 + + 6,306.24 + + 15,898.25 +
      + Product Attachment + + Drink + + All Gender + + 713 + + 555.05 + + 1,403.65 +
      + Product Attachment + + Food + + All Gender + + 5,441 + + 4,571.71 + + 11,525.25 +
      + Product Attachment + + Baked Goods + + All Gender + + 213 + + 175.69 + + 445.60 +
      + Product Attachment + + Baking Goods + + All Gender + + 547 + + 410.31 + + 1,032.59 +
      + Product Attachment + + Baking Goods + + All Gender + + 258 + + 191.48 + + 470.58 +
      + Product Attachment + + Jams and Jellies + + All Gender + + 289 + + 218.83 + + 562.01 +
      + Product Attachment + + Jam + + All Gender + + 66 + + 48.03 + + 128.68 +
      + Product Attachment + + Jelly + + All Gender + + 45 + + 34.12 + + 90.62 +
      + Product Attachment + + Peanut Butter + + All Gender + + 63 + + 47.71 + + 122.31 +
      + Product Attachment + + BBB Best + + All Gender + + 15 + + 14.53 + + 38.46 +
      + Product Attachment + + CDR + + All Gender + + 13 + + 11.94 + + 30.57 +
      + Product Attachment + + Landslide + + All Gender + + 12 + + 5.32 + + 14.28 +
      + Product Attachment + + Plato + + All Gender + + 9 + + 7.16 + + 17.43 +
      + Product Attachment + + Super + + All Gender + + 14 + + 8.75 + + 21.57 +
      + Product Attachment + + Preserves + + All Gender + + 115 + + 88.98 + + 220.40 +
      + Product Attachment + + Breakfast Foods + + All Gender + + 103 + + 87.35 + + 220.75 +
      + Product Attachment + + Canned Foods + + All Gender + + 564 + + 463.28 + + 1,154.91 +
      + Product Attachment + + Canned Products + + All Gender + + 60 + + 51.61 + + 124.24 +
      + Product Attachment + + Dairy + + All Gender + + 355 + + 339.81 + + 849.78 +
      + Product Attachment + + Deli + + All Gender + + 324 + + 243.64 + + 618.23 +
      + Product Attachment + + Eggs + + All Gender + + 118 + + 97.43 + + 241.21 +
      + Product Attachment + + Frozen Foods + + All Gender + + 812 + + 665.48 + + 1,692.11 +
      + Product Attachment + + Meat + + All Gender + + 54 + + 51.36 + + 127.83 +
      + Product Attachment + + Produce + + All Gender + + 1,069 + + 909.24 + + 2,287.61 +
      + Product Attachment + + Seafood + + All Gender + + 45 + + 36.98 + + 100.61 +
      + Product Attachment + + Snack Foods + + All Gender + + 819 + + 726.73 + + 1,847.28 +
      + Product Attachment + + Snacks + + All Gender + + 209 + + 186.22 + + 450.03 +
      + Product Attachment + + Starchy Foods + + All Gender + + 149 + + 126.59 + + 332.47 +
      + Product Attachment + + Non-Consumable + + All Gender + + 1,390 + + 1,179.48 + + 2,969.35 +
      + Product Attachment + + Carousel + + All Gender + + 14 + + 7.99 + + 21.21 +
      + Product Attachment + + Checkout + + All Gender + + 48 + + 40.45 + + 100.61 +
      + Product Attachment + + Health and Hygiene + + All Gender + + 440 + + 356.54 + + 901.73 +
      + Product Attachment + + Household + + All Gender + + 777 + + 690.03 + + 1,737.96 +
      + Product Attachment + + Periodicals + + All Gender + + 111 + + 84.48 + + 207.84 +
      + Radio + + All Products + + All Gender + + 2,454 + + 2,087.51 + + 5,213.61 +
      + Radio + + Drink + + All Gender + + 226 + + 182.85 + + 443.68 +
      + Radio + + Food + + All Gender + + 1,733 + + 1,485.25 + + 3,727.36 +
      + Radio + + Baked Goods + + All Gender + + 83 + + 76.51 + + 186.20 +
      + Radio + + Baking Goods + + All Gender + + 157 + + 109.10 + + 274.90 +
      + Radio + + Baking Goods + + All Gender + + 63 + + 45.02 + + 110.43 +
      + Radio + + Jams and Jellies + + All Gender + + 94 + + 64.08 + + 164.47 +
      + Radio + + Jam + + All Gender + + 15 + + 10.42 + + 26.94 +
      + Radio + + Jelly + + All Gender + + 24 + + 14.54 + + 37.49 +
      + Radio + + Peanut Butter + + All Gender + + 19 + + 16.85 + + 41.82 +
      + Radio + + BBB Best + + All Gender + + 10 + + 10.58 + + 24.44 +
      + Radio + + CDR + + All Gender + +   + +   + +   +
      + Radio + + Landslide + + All Gender + +   + +   + +   +
      + Radio + + Plato + + All Gender + + 4 + + 3.77 + + 9.80 +
      + Radio + + Super + + All Gender + + 5 + + 2.50 + + 7.58 +
      + Radio + + Preserves + + All Gender + + 36 + + 22.28 + + 58.22 +
      + Radio + + Breakfast Foods + + All Gender + + 25 + + 18.78 + + 50.22 +
      + Radio + + Canned Foods + + All Gender + + 158 + + 124.79 + + 307.55 +
      + Radio + + Canned Products + + All Gender + + 22 + + 17.29 + + 43.42 +
      + Radio + + Dairy + + All Gender + + 112 + + 92.12 + + 216.79 +
      + Radio + + Deli + + All Gender + + 129 + + 119.14 + + 307.25 +
      + Radio + + Eggs + + All Gender + + 25 + + 29.97 + + 71.15 +
      + Radio + + Frozen Foods + + All Gender + + 253 + + 202.71 + + 507.45 +
      + Radio + + Meat + + All Gender + + 12 + + 11.53 + + 32.85 +
      + Radio + + Produce + + All Gender + + 336 + + 292.05 + + 738.20 +
      + Radio + + Seafood + + All Gender + + 15 + + 13.28 + + 35.58 +
      + Radio + + Snack Foods + + All Gender + + 290 + + 270.59 + + 674.73 +
      + Radio + + Snacks + + All Gender + + 60 + + 55.67 + + 144.58 +
      + Radio + + Starchy Foods + + All Gender + + 56 + + 51.72 + + 136.49 +
      + Radio + + Non-Consumable + + All Gender + + 495 + + 419.41 + + 1,042.57 +
      + Radio + + Carousel + + All Gender + + 15 + + 11.15 + + 26.85 +
      + Radio + + Checkout + + All Gender + + 21 + + 17.00 + + 42.74 +
      + Radio + + Health and Hygiene + + All Gender + + 145 + + 114.84 + + 289.80 +
      + Radio + + Household + + All Gender + + 258 + + 233.31 + + 575.07 +
      + Radio + + Periodicals + + All Gender + + 56 + + 43.12 + + 108.11 +
      + Street Handout + + All Products + + All Gender + + 5,753 + + 4,856.54 + + 12,192.90 +
      + Street Handout + + Drink + + All Gender + + 512 + + 372.68 + + 943.42 +
      + Street Handout + + Food + + All Gender + + 4,239 + + 3,650.32 + + 9,151.65 +
      + Street Handout + + Baked Goods + + All Gender + + 160 + + 120.12 + + 301.62 +
      + Street Handout + + Baking Goods + + All Gender + + 498 + + 373.67 + + 923.22 +
      + Street Handout + + Baking Goods + + All Gender + + 200 + + 144.16 + + 357.82 +
      + Street Handout + + Jams and Jellies + + All Gender + + 298 + + 229.51 + + 565.40 +
      + Street Handout + + Jam + + All Gender + + 53 + + 44.30 + + 112.95 +
      + Street Handout + + Jelly + + All Gender + + 92 + + 63.14 + + 155.59 +
      + Street Handout + + Peanut Butter + + All Gender + + 51 + + 51.06 + + 118.90 +
      + Street Handout + + BBB Best + + All Gender + + 11 + + 10.85 + + 25.72 +
      + Street Handout + + CDR + + All Gender + + 8 + + 9.06 + + 19.73 +
      + Street Handout + + Landslide + + All Gender + + 11 + + 6.90 + + 15.54 +
      + Street Handout + + Plato + + All Gender + + 9 + + 8.47 + + 20.89 +
      + Street Handout + + Super + + All Gender + + 12 + + 15.78 + + 37.02 +
      + Street Handout + + Preserves + + All Gender + + 102 + + 71.02 + + 177.96 +
      + Street Handout + + Breakfast Foods + + All Gender + + 81 + + 74.32 + + 192.90 +
      + Street Handout + + Canned Foods + + All Gender + + 459 + + 413.21 + + 1,021.86 +
      + Street Handout + + Canned Products + + All Gender + + 30 + + 19.43 + + 45.68 +
      + Street Handout + + Dairy + + All Gender + + 301 + + 285.98 + + 718.61 +
      + Street Handout + + Deli + + All Gender + + 305 + + 253.54 + + 638.30 +
      + Street Handout + + Eggs + + All Gender + + 66 + + 59.15 + + 156.82 +
      + Street Handout + + Frozen Foods + + All Gender + + 612 + + 520.12 + + 1,313.71 +
      + Street Handout + + Meat + + All Gender + + 37 + + 29.82 + + 78.24 +
      + Street Handout + + Produce + + All Gender + + 745 + + 662.39 + + 1,639.94 +
      + Street Handout + + Seafood + + All Gender + + 37 + + 30.12 + + 72.77 +
      + Street Handout + + Snack Foods + + All Gender + + 675 + + 600.23 + + 1,515.68 +
      + Street Handout + + Snacks + + All Gender + + 144 + + 128.79 + + 321.16 +
      + Street Handout + + Starchy Foods + + All Gender + + 89 + + 79.43 + + 211.14 +
      + Street Handout + + Non-Consumable + + All Gender + + 1,002 + + 833.53 + + 2,097.83 +
      + Street Handout + + Carousel + + All Gender + + 17 + + 13.53 + + 30.98 +
      + Street Handout + + Checkout + + All Gender + + 45 + + 34.77 + + 85.38 +
      + Street Handout + + Health and Hygiene + + All Gender + + 402 + + 318.03 + + 802.92 +
      + Street Handout + + Household + + All Gender + + 501 + + 436.41 + + 1,105.38 +
      + Street Handout + + Periodicals + + All Gender + + 37 + + 30.80 + + 73.17 +
      + Sunday Paper + + All Products + + All Gender + + 4,339 + + 3,673.86 + + 9,092.89 +
      + Sunday Paper + + Drink + + All Gender + + 430 + + 345.53 + + 856.73 +
      + Sunday Paper + + Food + + All Gender + + 3,106 + + 2,646.47 + + 6,559.46 +
      + Sunday Paper + + Baked Goods + + All Gender + + 140 + + 110.79 + + 282.55 +
      + Sunday Paper + + Baking Goods + + All Gender + + 338 + + 239.76 + + 603.86 +
      + Sunday Paper + + Baking Goods + + All Gender + + 170 + + 118.05 + + 298.79 +
      + Sunday Paper + + Jams and Jellies + + All Gender + + 168 + + 121.71 + + 305.07 +
      + Sunday Paper + + Jam + + All Gender + + 24 + + 22.35 + + 54.83 +
      + Sunday Paper + + Jelly + + All Gender + + 27 + + 18.20 + + 47.12 +
      + Sunday Paper + + Peanut Butter + + All Gender + + 51 + + 37.67 + + 96.67 +
      + Sunday Paper + + BBB Best + + All Gender + + 10 + + 6.08 + + 16.22 +
      + Sunday Paper + + CDR + + All Gender + + 10 + + 10.47 + + 26.50 +
      + Sunday Paper + + Landslide + + All Gender + + 15 + + 6.20 + + 16.31 +
      + Sunday Paper + + Plato + + All Gender + + 16 + + 14.93 + + 37.64 +
      + Sunday Paper + + Super + + All Gender + +   + +   + +   +
      + Sunday Paper + + Preserves + + All Gender + + 66 + + 43.49 + + 106.45 +
      + Sunday Paper + + Breakfast Foods + + All Gender + + 55 + + 49.80 + + 120.23 +
      + Sunday Paper + + Canned Foods + + All Gender + + 283 + + 249.46 + + 605.11 +
      + Sunday Paper + + Canned Products + + All Gender + + 34 + + 29.65 + + 72.18 +
      + Sunday Paper + + Dairy + + All Gender + + 200 + + 201.94 + + 497.91 +
      + Sunday Paper + + Deli + + All Gender + + 228 + + 188.37 + + 467.53 +
      + Sunday Paper + + Eggs + + All Gender + + 54 + + 47.68 + + 118.44 +
      + Sunday Paper + + Frozen Foods + + All Gender + + 425 + + 330.81 + + 839.15 +
      + Sunday Paper + + Meat + + All Gender + + 18 + + 19.85 + + 52.20 +
      + Sunday Paper + + Produce + + All Gender + + 603 + + 520.95 + + 1,274.70 +
      + Sunday Paper + + Seafood + + All Gender + + 27 + + 26.82 + + 69.49 +
      + Sunday Paper + + Snack Foods + + All Gender + + 469 + + 413.18 + + 1,027.98 +
      + Sunday Paper + + Snacks + + All Gender + + 123 + + 108.50 + + 261.38 +
      + Sunday Paper + + Starchy Foods + + All Gender + + 109 + + 108.91 + + 266.75 +
      + Sunday Paper + + Non-Consumable + + All Gender + + 803 + + 681.86 + + 1,676.70 +
      + Sunday Paper + + Carousel + + All Gender + + 7 + + 6.70 + + 14.68 +
      + Sunday Paper + + Checkout + + All Gender + + 17 + + 13.09 + + 30.89 +
      + Sunday Paper + + Health and Hygiene + + All Gender + + 278 + + 227.06 + + 565.99 +
      + Sunday Paper + + Household + + All Gender + + 420 + + 371.58 + + 911.69 +
      + Sunday Paper + + Periodicals + + All Gender + + 81 + + 63.43 + + 153.45 +
      + Sunday Paper, Radio + + All Products + + All Gender + + 5,945 + + 5,027.31 + + 12,551.96 +
      + Sunday Paper, Radio + + Drink + + All Gender + + 591 + + 454.03 + + 1,129.94 +
      + Sunday Paper, Radio + + Food + + All Gender + + 4,239 + + 3,612.38 + + 9,033.23 +
      + Sunday Paper, Radio + + Baked Goods + + All Gender + + 152 + + 109.11 + + 274.39 +
      + Sunday Paper, Radio + + Baking Goods + + All Gender + + 482 + + 367.13 + + 913.84 +
      + Sunday Paper, Radio + + Baking Goods + + All Gender + + 206 + + 152.72 + + 381.59 +
      + Sunday Paper, Radio + + Jams and Jellies + + All Gender + + 276 + + 214.41 + + 532.25 +
      + Sunday Paper, Radio + + Jam + + All Gender + + 52 + + 52.39 + + 126.62 +
      + Sunday Paper, Radio + + Jelly + + All Gender + + 74 + + 53.93 + + 135.03 +
      + Sunday Paper, Radio + + Peanut Butter + + All Gender + + 64 + + 50.10 + + 126.71 +
      + Sunday Paper, Radio + + BBB Best + + All Gender + + 14 + + 11.58 + + 27.40 +
      + Sunday Paper, Radio + + CDR + + All Gender + + 17 + + 14.68 + + 41.25 +
      + Sunday Paper, Radio + + Landslide + + All Gender + + 14 + + 6.62 + + 17.04 +
      + Sunday Paper, Radio + + Plato + + All Gender + + 7 + + 6.91 + + 17.15 +
      + Sunday Paper, Radio + + Super + + All Gender + + 12 + + 10.31 + + 23.87 +
      + Sunday Paper, Radio + + Preserves + + All Gender + + 86 + + 57.99 + + 143.89 +
      + Sunday Paper, Radio + + Breakfast Foods + + All Gender + + 80 + + 62.80 + + 154.04 +
      + Sunday Paper, Radio + + Canned Foods + + All Gender + + 456 + + 361.79 + + 914.81 +
      + Sunday Paper, Radio + + Canned Products + + All Gender + + 45 + + 39.72 + + 95.88 +
      + Sunday Paper, Radio + + Dairy + + All Gender + + 283 + + 296.91 + + 722.75 +
      + Sunday Paper, Radio + + Deli + + All Gender + + 252 + + 190.32 + + 479.59 +
      + Sunday Paper, Radio + + Eggs + + All Gender + + 114 + + 104.65 + + 256.15 +
      + Sunday Paper, Radio + + Frozen Foods + + All Gender + + 599 + + 490.33 + + 1,222.54 +
      + Sunday Paper, Radio + + Meat + + All Gender + + 40 + + 31.66 + + 84.76 +
      + Sunday Paper, Radio + + Produce + + All Gender + + 858 + + 752.62 + + 1,886.01 +
      + Sunday Paper, Radio + + Seafood + + All Gender + + 27 + + 20.66 + + 50.39 +
      + Sunday Paper, Radio + + Snack Foods + + All Gender + + 596 + + 555.70 + + 1,402.21 +
      + Sunday Paper, Radio + + Snacks + + All Gender + + 147 + + 120.43 + + 304.18 +
      + Sunday Paper, Radio + + Starchy Foods + + All Gender + + 108 + + 108.55 + + 271.69 +
      + Sunday Paper, Radio + + Non-Consumable + + All Gender + + 1,115 + + 960.90 + + 2,388.79 +
      + Sunday Paper, Radio + + Carousel + + All Gender + + 18 + + 10.99 + + 26.94 +
      + Sunday Paper, Radio + + Checkout + + All Gender + + 26 + + 24.68 + + 62.14 +
      + Sunday Paper, Radio + + Health and Hygiene + + All Gender + + 378 + + 309.37 + + 771.48 +
      + Sunday Paper, Radio + + Household + + All Gender + + 585 + + 516.99 + + 1,276.16 +
      + Sunday Paper, Radio + + Periodicals + + All Gender + + 108 + + 98.86 + + 252.07 +
      + Sunday Paper, Radio, TV + + All Products + + All Gender + + 2,726 + + 2,341.58 + + 5,819.33 +
      + Sunday Paper, Radio, TV + + Drink + + All Gender + + 225 + + 163.09 + + 403.51 +
      + Sunday Paper, Radio, TV + + Food + + All Gender + + 2,021 + + 1,762.18 + + 4,377.85 +
      + Sunday Paper, Radio, TV + + Baked Goods + + All Gender + + 67 + + 66.17 + + 163.29 +
      + Sunday Paper, Radio, TV + + Baking Goods + + All Gender + + 228 + + 182.98 + + 455.90 +
      + Sunday Paper, Radio, TV + + Baking Goods + + All Gender + + 90 + + 73.09 + + 176.63 +
      + Sunday Paper, Radio, TV + + Jams and Jellies + + All Gender + + 138 + + 109.90 + + 279.27 +
      + Sunday Paper, Radio, TV + + Jam + + All Gender + + 37 + + 31.30 + + 78.56 +
      + Sunday Paper, Radio, TV + + Jelly + + All Gender + + 27 + + 16.18 + + 39.92 +
      + Sunday Paper, Radio, TV + + Peanut Butter + + All Gender + + 30 + + 24.01 + + 64.19 +
      + Sunday Paper, Radio, TV + + BBB Best + + All Gender + + 11 + + 9.78 + + 23.86 +
      + Sunday Paper, Radio, TV + + CDR + + All Gender + +   + +   + +   +
      + Sunday Paper, Radio, TV + + Landslide + + All Gender + + 4 + + 2.39 + + 5.68 +
      + Sunday Paper, Radio, TV + + Plato + + All Gender + + 5 + + 3.85 + + 11.60 +
      + Sunday Paper, Radio, TV + + Super + + All Gender + + 10 + + 7.99 + + 23.05 +
      + Sunday Paper, Radio, TV + + Preserves + + All Gender + + 44 + + 38.41 + + 96.60 +
      + Sunday Paper, Radio, TV + + Breakfast Foods + + All Gender + + 38 + + 32.76 + + 89.85 +
      + Sunday Paper, Radio, TV + + Canned Foods + + All Gender + + 180 + + 138.77 + + 340.04 +
      + Sunday Paper, Radio, TV + + Canned Products + + All Gender + + 14 + + 12.00 + + 28.28 +
      + Sunday Paper, Radio, TV + + Dairy + + All Gender + + 121 + + 125.32 + + 305.43 +
      + Sunday Paper, Radio, TV + + Deli + + All Gender + + 131 + + 98.93 + + 245.42 +
      + Sunday Paper, Radio, TV + + Eggs + + All Gender + + 39 + + 39.57 + + 91.99 +
      + Sunday Paper, Radio, TV + + Frozen Foods + + All Gender + + 279 + + 207.59 + + 514.95 +
      + Sunday Paper, Radio, TV + + Meat + + All Gender + + 12 + + 11.77 + + 30.23 +
      + Sunday Paper, Radio, TV + + Produce + + All Gender + + 411 + + 382.14 + + 943.93 +
      + Sunday Paper, Radio, TV + + Seafood + + All Gender + + 31 + + 28.07 + + 69.82 +
      + Sunday Paper, Radio, TV + + Snack Foods + + All Gender + + 346 + + 318.26 + + 798.50 +
      + Sunday Paper, Radio, TV + + Snacks + + All Gender + + 75 + + 65.49 + + 174.02 +
      + Sunday Paper, Radio, TV + + Starchy Foods + + All Gender + + 49 + + 52.37 + + 126.20 +
      + Sunday Paper, Radio, TV + + Non-Consumable + + All Gender + + 480 + + 416.30 + + 1,037.97 +
      + Sunday Paper, Radio, TV + + Carousel + + All Gender + + 21 + + 11.63 + + 27.92 +
      + Sunday Paper, Radio, TV + + Checkout + + All Gender + + 10 + + 8.12 + + 19.80 +
      + Sunday Paper, Radio, TV + + Health and Hygiene + + All Gender + + 138 + + 110.35 + + 276.31 +
      + Sunday Paper, Radio, TV + + Household + + All Gender + + 262 + + 244.90 + + 608.52 +
      + Sunday Paper, Radio, TV + + Periodicals + + All Gender + + 49 + + 41.30 + + 105.42 +
      + TV + + All Products + + All Gender + + 3,607 + + 3,116.40 + + 7,786.21 +
      + TV + + Drink + + All Gender + + 332 + + 283.18 + + 721.07 +
      + TV + + Food + + All Gender + + 2,563 + + 2,238.13 + + 5,573.27 +
      + TV + + Baked Goods + + All Gender + + 114 + + 103.40 + + 262.97 +
      + TV + + Baking Goods + + All Gender + + 237 + + 185.55 + + 464.23 +
      + TV + + Baking Goods + + All Gender + + 95 + + 74.29 + + 190.59 +
      + TV + + Jams and Jellies + + All Gender + + 142 + + 111.25 + + 273.64 +
      + TV + + Jam + + All Gender + + 38 + + 32.28 + + 77.58 +
      + TV + + Jelly + + All Gender + + 35 + + 24.64 + + 63.38 +
      + TV + + Peanut Butter + + All Gender + + 31 + + 21.83 + + 56.80 +
      + TV + + BBB Best + + All Gender + +   + +   + +   +
      + TV + + CDR + + All Gender + + 11 + + 9.78 + + 27.19 +
      + TV + + Landslide + + All Gender + + 7 + + 2.61 + + 7.12 +
      + TV + + Plato + + All Gender + + 6 + + 4.95 + + 12.13 +
      + TV + + Super + + All Gender + + 7 + + 4.48 + + 10.36 +
      + TV + + Preserves + + All Gender + + 38 + + 32.51 + + 75.88 +
      + TV + + Breakfast Foods + + All Gender + + 36 + + 30.11 + + 79.89 +
      + TV + + Canned Foods + + All Gender + + 240 + + 200.00 + + 519.91 +
      + TV + + Canned Products + + All Gender + + 26 + + 15.00 + + 38.65 +
      + TV + + Dairy + + All Gender + + 179 + + 183.73 + + 458.87 +
      + TV + + Deli + + All Gender + + 155 + + 139.76 + + 342.51 +
      + TV + + Eggs + + All Gender + + 42 + + 32.74 + + 80.93 +
      + TV + + Frozen Foods + + All Gender + + 352 + + 300.42 + + 738.40 +
      + TV + + Meat + + All Gender + + 22 + + 19.76 + + 49.27 +
      + TV + + Produce + + All Gender + + 543 + + 456.53 + + 1,145.45 +
      + TV + + Seafood + + All Gender + + 34 + + 30.71 + + 75.47 +
      + TV + + Snack Foods + + All Gender + + 401 + + 377.01 + + 927.50 +
      + TV + + Snacks + + All Gender + + 99 + + 92.80 + + 220.54 +
      + TV + + Starchy Foods + + All Gender + + 83 + + 70.61 + + 168.68 +
      + TV + + Non-Consumable + + All Gender + + 712 + + 595.08 + + 1,491.87 +
      + TV + + Carousel + + All Gender + + 4 + + 3.13 + + 9.20 +
      + TV + + Checkout + + All Gender + + 34 + + 34.12 + + 86.21 +
      + TV + + Health and Hygiene + + All Gender + + 249 + + 196.08 + + 486.46 +
      + TV + + Household + + All Gender + + 361 + + 316.09 + + 795.40 +
      + TV + + Periodicals + + All Gender + + 64 + + 45.67 + + 114.60 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/insane-rows-true-false-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/insane-rows-true-false-true-result.html index 330fed3f..658bfa3c 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/insane-rows-true-false-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/insane-rows-true-false-true-result.html @@ -1,12179 +1,12179 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - All Products - - All Gender - - 266,773 - - 225,627.23 - - 565,238.13 -
      - All Media - - All Products - - Drink - - All Gender - - 24,597 - - 19,477.23 - - 48,836.21 -
      - All Media - - All Products - - Food - - All Gender - - 191,940 - - 163,270.72 - - 409,035.59 -
      - All Media - - All Products - - Food - - Baked Goods - - All Gender - - 7,870 - - 6,564.09 - - 16,455.43 -
      - All Media - - All Products - - Food - - Baking Goods - - All Gender - - 20,245 - - 15,370.61 - - 38,670.41 -
      - All Media - - All Products - - Food - - Baking Goods - - Baking Goods - - All Gender - - 8,357 - - 6,123.32 - - 15,446.69 -
      - All Media - - All Products - - Food - - Baking Goods - - Baking Goods - - All Gender - - F - - 4,005 - - 2,907.70 - - 7,313.61 -
      - All Media - - All Products - - Food - - Baking Goods - - Baking Goods - - All Gender - - M - - 4,352 - - 3,215.62 - - 8,133.08 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - All Gender - - 11,888 - - 9,247.29 - - 23,223.72 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jam - - All Gender - - 2,556 - - 2,132.27 - - 5,401.81 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jelly - - All Gender - - 2,565 - - 1,830.04 - - 4,609.61 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jelly - - All Gender - - F - - 1,309 - - 956.94 - - 2,414.94 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jelly - - All Gender - - M - - 1,256 - - 873.10 - - 2,194.67 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - All Gender - - 2,667 - - 2,097.37 - - 5,231.08 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - All Gender - - 556 - - 424.38 - - 1,055.72 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - All Gender - - F - - 271 - - 201.08 - - 500.39 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - All Gender - - M - - 285 - - 223.30 - - 555.33 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - BBB Best Chunky Peanut Butter - - All Gender - - 188 - - 147.32 - - 370.36 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - BBB Best Chunky Peanut Butter - - All Gender - - F - - 107 - - 85.81 - - 210.79 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - BBB Best Chunky Peanut Butter - - All Gender - - M - - 81 - - 61.50 - - 159.57 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - BBB Best Creamy Peanut Butter - - All Gender - - 201 - - 87.86 - - 221.10 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - BBB Best Creamy Peanut Butter - - All Gender - - F - - 99 - - 43.35 - - 108.90 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - BBB Best Creamy Peanut Butter - - All Gender - - M - - 102 - - 44.51 - - 112.20 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - BBB Best Extra Chunky Peanut Butter - - All Gender - - 167 - - 189.21 - - 464.26 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - BBB Best Extra Chunky Peanut Butter - - All Gender - - F - - 65 - - 71.92 - - 180.70 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - BBB Best Extra Chunky Peanut Butter - - All Gender - - M - - 102 - - 117.29 - - 283.56 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - CDR - - All Gender - - 545 - - 538.88 - - 1,326.30 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Landslide - - All Gender - - 531 - - 256.16 - - 635.29 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Plato - - All Gender - - 520 - - 447.73 - - 1,132.16 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Super - - All Gender - - 515 - - 430.21 - - 1,081.61 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Preserves - - All Gender - - 4,100 - - 3,187.61 - - 7,981.22 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Preserves - - All Gender - - F - - 1,946 - - 1,472.42 - - 3,717.80 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Preserves - - All Gender - - M - - 2,154 - - 1,715.19 - - 4,263.42 -
      - All Media - - All Products - - Food - - Breakfast Foods - - All Gender - - 3,317 - - 2,756.80 - - 6,941.46 -
      - All Media - - All Products - - Food - - Canned Foods - - All Gender - - 19,026 - - 15,894.53 - - 39,774.34 -
      - All Media - - All Products - - Food - - Canned Foods - - Canned Anchovies - - All Gender - - 900 - - 913.88 - - 2,296.38 -
      - All Media - - All Products - - Food - - Canned Foods - - Canned Clams - - All Gender - - 882 - - 759.80 - - 1,912.68 -
      - All Media - - All Products - - Food - - Canned Foods - - Canned Clams - - Clams - - All Gender - - 882 - - 759.80 - - 1,912.68 -
      - All Media - - All Products - - Food - - Canned Foods - - Canned Clams - - Clams - - Better - - All Gender - - 189 - - 151.14 - - 398.79 -
      - All Media - - All Products - - Food - - Canned Foods - - Canned Clams - - Clams - - Blue Label - - All Gender - - 165 - - 112.82 - - 278.85 -
      - All Media - - All Products - - Food - - Canned Foods - - Canned Clams - - Clams - - Bravo - - All Gender - - 184 - - 280.70 - - 708.40 -
      - All Media - - All Products - - Food - - Canned Foods - - Canned Clams - - Clams - - Just Right - - All Gender - - 177 - - 161.96 - - 394.71 -
      - All Media - - All Products - - Food - - Canned Foods - - Canned Clams - - Clams - - Pleasant - - All Gender - - 167 - - 53.17 - - 131.93 -
      - All Media - - All Products - - Food - - Canned Foods - - Canned Oysters - - All Gender - - 708 - - 571.50 - - 1,442.77 -
      - All Media - - All Products - - Food - - Canned Foods - - Canned Sardines - - All Gender - - 819 - - 537.59 - - 1,357.80 -
      - All Media - - All Products - - Food - - Canned Foods - - Canned Shrimp - - All Gender - - 804 - - 858.39 - - 2,146.49 -
      - All Media - - All Products - - Food - - Canned Foods - - Canned Soup - - All Gender - - 8,006 - - 6,408.29 - - 15,966.10 -
      - All Media - - All Products - - Food - - Canned Foods - - Canned Tuna - - All Gender - - 1,710 - - 1,288.52 - - 3,210.76 -
      - All Media - - All Products - - Food - - Canned Foods - - Vegetables - - All Gender - - 5,197 - - 4,556.57 - - 11,441.36 -
      - All Media - - All Products - - Food - - Canned Products - - All Gender - - 1,812 - - 1,317.13 - - 3,314.52 -
      - All Media - - All Products - - Food - - Dairy - - All Gender - - 12,885 - - 12,228.85 - - 30,508.85 -
      - All Media - - All Products - - Food - - Deli - - All Gender - - 12,037 - - 10,108.87 - - 25,318.93 -
      - All Media - - All Products - - Food - - Deli - - Meat - - All Gender - - 9,433 - - 8,215.81 - - 20,616.29 -
      - All Media - - All Products - - Food - - Deli - - Meat - - Bologna - - All Gender - - 2,588 - - 2,340.24 - - 5,859.95 -
      - All Media - - All Products - - Food - - Deli - - Meat - - Deli Meats - - All Gender - - 3,339 - - 2,851.18 - - 7,191.24 -
      - All Media - - All Products - - Food - - Deli - - Meat - - Deli Meats - - All Gender - - F - - 1,653 - - 1,414.49 - - 3,579.34 -
      - All Media - - All Products - - Food - - Deli - - Meat - - Deli Meats - - All Gender - - M - - 1,686 - - 1,436.69 - - 3,611.90 -
      - All Media - - All Products - - Food - - Deli - - Meat - - Fresh Chicken - - All Gender - - 878 - - 842.85 - - 2,091.52 -
      - All Media - - All Products - - Food - - Deli - - Meat - - Hot Dogs - - All Gender - - 2,628 - - 2,181.55 - - 5,473.58 -
      - All Media - - All Products - - Food - - Deli - - Side Dishes - - All Gender - - 2,604 - - 1,893.06 - - 4,702.64 -
      - All Media - - All Products - - Food - - Eggs - - All Gender - - 4,132 - - 3,684.90 - - 9,200.76 -
      - All Media - - All Products - - Food - - Frozen Foods - - All Gender - - 26,655 - - 22,030.66 - - 55,207.50 -
      - All Media - - All Products - - Food - - Meat - - All Gender - - 1,714 - - 1,465.42 - - 3,669.89 -
      - All Media - - All Products - - Food - - Produce - - All Gender - - 37,792 - - 32,831.33 - - 82,248.42 -
      - All Media - - All Products - - Food - - Seafood - - All Gender - - 1,764 - - 1,520.70 - - 3,809.14 -
      - All Media - - All Products - - Food - - Snack Foods - - All Gender - - 30,545 - - 26,963.34 - - 67,609.82 -
      - All Media - - All Products - - Food - - Snacks - - All Gender - - 6,884 - - 5,827.58 - - 14,550.05 -
      - All Media - - All Products - - Food - - Starchy Foods - - All Gender - - 5,262 - - 4,705.91 - - 11,756.07 -
      - All Media - - All Products - - Non-Consumable - - All Gender - - 50,236 - - 42,879.28 - - 107,366.33 -
      - All Media - - All Products - - Non-Consumable - - Carousel - - All Gender - - 841 - - 595.97 - - 1,500.11 -
      - All Media - - All Products - - Non-Consumable - - Checkout - - All Gender - - 1,779 - - 1,525.04 - - 3,767.71 -
      - All Media - - All Products - - Non-Consumable - - Health and Hygiene - - All Gender - - 16,284 - - 12,972.99 - - 32,571.86 -
      - All Media - - All Products - - Non-Consumable - - Household - - All Gender - - 27,038 - - 24,170.73 - - 60,469.89 -
      - All Media - - All Products - - Non-Consumable - - Periodicals - - All Gender - - 4,294 - - 3,614.55 - - 9,056.76 -
      - All Media - - Bulk Mail - - All Products - - All Gender - - 4,320 - - 3,740.95 - - 9,349.07 -
      - All Media - - Cash Register Handout - - All Products - - All Gender - - 6,697 - - 5,715.67 - - 14,321.33 -
      - All Media - - Daily Paper - - All Products - - All Gender - - 7,738 - - 6,559.23 - - 16,479.81 -
      - All Media - - Daily Paper, Radio - - All Products - - All Gender - - 6,891 - - 5,668.77 - - 14,169.42 -
      - All Media - - Daily Paper, Radio, TV - - All Products - - All Gender - - 9,513 - - 8,055.22 - - 20,173.97 -
      - All Media - - In-Store Coupon - - All Products - - All Gender - - 3,798 - - 3,263.11 - - 8,162.46 -
      - All Media - - In-Store Coupon - - All Products - - Drink - - All Gender - - 345 - - 282.44 - - 708.38 -
      - All Media - - In-Store Coupon - - All Products - - Food - - All Gender - - 2,737 - - 2,345.57 - - 5,889.34 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Baked Goods - - All Gender - - 131 - - 114.11 - - 279.11 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Baking Goods - - All Gender - - 308 - - 252.88 - - 632.01 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Baking Goods - - Baking Goods - - All Gender - - 146 - - 103.30 - - 261.44 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Baking Goods - - Jams and Jellies - - All Gender - - 162 - - 149.58 - - 370.57 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jam - - All Gender - - 55 - - 58.16 - - 141.19 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jelly - - All Gender - - 32 - - 23.96 - - 62.12 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - All Gender - - 22 - - 19.54 - - 48.72 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - All Gender - - 7 - - 6.72 - - 16.10 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - CDR - - All Gender - - 10 - - 9.81 - - 24.32 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Landslide - - All Gender - -   - -   - -   -
      - All Media - - In-Store Coupon - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Plato - - All Gender - - 3 - - 2.32 - - 6.32 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Super - - All Gender - - 2 - - .69 - - 1.98 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Preserves - - All Gender - - 53 - - 47.92 - - 118.54 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Breakfast Foods - - All Gender - - 59 - - 49.22 - - 125.19 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Breakfast Foods - - All Gender - - F - - 33 - - 22.88 - - 54.84 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Breakfast Foods - - All Gender - - M - - 26 - - 26.34 - - 70.35 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Canned Foods - - All Gender - - 245 - - 200.61 - - 506.67 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Canned Products - - All Gender - - 15 - - 9.58 - - 26.17 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Dairy - - All Gender - - 166 - - 153.42 - - 372.01 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Deli - - All Gender - - 180 - - 163.58 - - 392.68 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Eggs - - All Gender - - 56 - - 42.51 - - 108.90 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Frozen Foods - - All Gender - - 374 - - 301.63 - - 773.52 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Meat - - All Gender - - 31 - - 23.91 - - 70.35 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Produce - - All Gender - - 563 - - 499.63 - - 1,257.05 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Seafood - - All Gender - - 34 - - 30.06 - - 76.09 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Snack Foods - - All Gender - - 439 - - 390.35 - - 989.13 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Snacks - - All Gender - - 78 - - 63.77 - - 153.02 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Starchy Foods - - All Gender - - 58 - - 50.30 - - 127.44 -
      - All Media - - In-Store Coupon - - All Products - - Non-Consumable - - All Gender - - 716 - - 635.10 - - 1,564.74 -
      - All Media - - In-Store Coupon - - All Products - - Non-Consumable - - Carousel - - All Gender - - 17 - - 8.77 - - 24.18 -
      - All Media - - In-Store Coupon - - All Products - - Non-Consumable - - Checkout - - All Gender - - 23 - - 15.20 - - 40.19 -
      - All Media - - In-Store Coupon - - All Products - - Non-Consumable - - Health and Hygiene - - All Gender - - 251 - - 193.53 - - 477.21 -
      - All Media - - In-Store Coupon - - All Products - - Non-Consumable - - Household - - All Gender - - 374 - - 375.66 - - 916.97 -
      - All Media - - In-Store Coupon - - All Products - - Non-Consumable - - Periodicals - - All Gender - - 51 - - 41.94 - - 106.19 -
      - All Media - - No Media - - All Products - - All Gender - - 195,448 - - 165,214.85 - - 414,026.92 -
      - All Media - - No Media - - All Products - - Drink - - All Gender - - 17,896 - - 14,211.41 - - 35,681.85 -
      - All Media - - No Media - - All Products - - Food - - All Gender - - 140,577 - - 119,469.36 - - 299,356.11 -
      - All Media - - No Media - - All Products - - Food - - Baked Goods - - All Gender - - 5,753 - - 4,775.86 - - 11,972.46 -
      - All Media - - No Media - - All Products - - Food - - Baking Goods - - All Gender - - 14,849 - - 11,226.15 - - 28,312.78 -
      - All Media - - No Media - - All Products - - Food - - Baking Goods - - Baking Goods - - All Gender - - 5,979 - - 4,347.34 - - 11,002.73 -
      - All Media - - No Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - All Gender - - 8,870 - - 6,878.81 - - 17,310.05 -
      - All Media - - No Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jam - - All Gender - - 1,883 - - 1,554.13 - - 3,965.74 -
      - All Media - - No Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jelly - - All Gender - - 1,936 - - 1,394.32 - - 3,504.71 -
      - All Media - - No Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - All Gender - - 1,984 - - 1,534.19 - - 3,828.01 -
      - All Media - - No Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - All Gender - - 406 - - 293.97 - - 735.29 -
      - All Media - - No Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - CDR - - All Gender - - 411 - - 401.88 - - 998.12 -
      - All Media - - No Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Landslide - - All Gender - - 401 - - 195.51 - - 478.44 -
      - All Media - - No Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Plato - - All Gender - - 384 - - 331.26 - - 832.92 -
      - All Media - - No Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Super - - All Gender - - 382 - - 311.57 - - 783.24 -
      - All Media - - No Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Preserves - - All Gender - - 3,067 - - 2,396.16 - - 6,011.59 -
      - All Media - - No Media - - All Products - - Food - - Breakfast Foods - - All Gender - - 2,418 - - 1,996.45 - - 5,016.10 -
      - All Media - - No Media - - All Products - - Food - - Canned Foods - - All Gender - - 13,861 - - 11,647.47 - - 29,102.79 -
      - All Media - - No Media - - All Products - - Food - - Canned Products - - All Gender - - 1,344 - - 960.82 - - 2,424.98 -
      - All Media - - No Media - - All Products - - Food - - Dairy - - All Gender - - 9,510 - - 8,981.13 - - 22,454.02 -
      - All Media - - No Media - - All Products - - Food - - Deli - - All Gender - - 8,695 - - 7,353.56 - - 18,410.26 -
      - All Media - - No Media - - All Products - - Food - - Eggs - - All Gender - - 2,976 - - 2,640.47 - - 6,606.25 -
      - All Media - - No Media - - All Products - - Food - - Frozen Foods - - All Gender - - 19,450 - - 16,127.24 - - 40,411.08 -
      - All Media - - No Media - - All Products - - Food - - Meat - - All Gender - - 1,236 - - 1,068.07 - - 2,646.00 -
      - All Media - - No Media - - All Products - - Food - - Produce - - All Gender - - 27,637 - - 24,036.36 - - 60,203.58 -
      - All Media - - No Media - - All Products - - Food - - Seafood - - All Gender - - 1,292 - - 1,114.69 - - 2,774.43 -
      - All Media - - No Media - - All Products - - Food - - Snack Foods - - All Gender - - 22,525 - - 19,800.82 - - 49,680.71 -
      - All Media - - No Media - - All Products - - Food - - Snacks - - All Gender - - 5,100 - - 4,264.55 - - 10,690.26 -
      - All Media - - No Media - - All Products - - Food - - Starchy Foods - - All Gender - - 3,931 - - 3,475.74 - - 8,650.41 -
      - All Media - - No Media - - All Products - - Non-Consumable - - All Gender - - 36,975 - - 31,534.08 - - 78,988.96 -
      - All Media - - No Media - - All Products - - Non-Consumable - - Carousel - - All Gender - - 584 - - 419.65 - - 1,050.75 -
      - All Media - - No Media - - All Products - - Non-Consumable - - Checkout - - All Gender - - 1,305 - - 1,113.97 - - 2,768.66 -
      - All Media - - No Media - - All Products - - Non-Consumable - - Health and Hygiene - - All Gender - - 11,845 - - 9,413.25 - - 23,621.12 -
      - All Media - - No Media - - All Products - - Non-Consumable - - Household - - All Gender - - 20,091 - - 17,929.20 - - 44,881.13 -
      - All Media - - No Media - - All Products - - Non-Consumable - - Periodicals - - All Gender - - 3,150 - - 2,658.00 - - 6,667.30 -
      - All Media - - Product Attachment - - All Products - - All Gender - - 7,544 - - 6,306.24 - - 15,898.25 -
      - All Media - - Product Attachment - - All Products - - Drink - - All Gender - - 713 - - 555.05 - - 1,403.65 -
      - All Media - - Product Attachment - - All Products - - Food - - All Gender - - 5,441 - - 4,571.71 - - 11,525.25 -
      - All Media - - Product Attachment - - All Products - - Food - - Baked Goods - - All Gender - - 213 - - 175.69 - - 445.60 -
      - All Media - - Product Attachment - - All Products - - Food - - Baking Goods - - All Gender - - 547 - - 410.31 - - 1,032.59 -
      - All Media - - Product Attachment - - All Products - - Food - - Baking Goods - - Baking Goods - - All Gender - - 258 - - 191.48 - - 470.58 -
      - All Media - - Product Attachment - - All Products - - Food - - Baking Goods - - Jams and Jellies - - All Gender - - 289 - - 218.83 - - 562.01 -
      - All Media - - Product Attachment - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jam - - All Gender - - 66 - - 48.03 - - 128.68 -
      - All Media - - Product Attachment - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jelly - - All Gender - - 45 - - 34.12 - - 90.62 -
      - All Media - - Product Attachment - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - All Gender - - 63 - - 47.71 - - 122.31 -
      - All Media - - Product Attachment - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - All Gender - - 15 - - 14.53 - - 38.46 -
      - All Media - - Product Attachment - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - CDR - - All Gender - - 13 - - 11.94 - - 30.57 -
      - All Media - - Product Attachment - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Landslide - - All Gender - - 12 - - 5.32 - - 14.28 -
      - All Media - - Product Attachment - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Plato - - All Gender - - 9 - - 7.16 - - 17.43 -
      - All Media - - Product Attachment - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Super - - All Gender - - 14 - - 8.75 - - 21.57 -
      - All Media - - Product Attachment - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Preserves - - All Gender - - 115 - - 88.98 - - 220.40 -
      - All Media - - Product Attachment - - All Products - - Food - - Breakfast Foods - - All Gender - - 103 - - 87.35 - - 220.75 -
      - All Media - - Product Attachment - - All Products - - Food - - Canned Foods - - All Gender - - 564 - - 463.28 - - 1,154.91 -
      - All Media - - Product Attachment - - All Products - - Food - - Canned Products - - All Gender - - 60 - - 51.61 - - 124.24 -
      - All Media - - Product Attachment - - All Products - - Food - - Dairy - - All Gender - - 355 - - 339.81 - - 849.78 -
      - All Media - - Product Attachment - - All Products - - Food - - Deli - - All Gender - - 324 - - 243.64 - - 618.23 -
      - All Media - - Product Attachment - - All Products - - Food - - Eggs - - All Gender - - 118 - - 97.43 - - 241.21 -
      - All Media - - Product Attachment - - All Products - - Food - - Frozen Foods - - All Gender - - 812 - - 665.48 - - 1,692.11 -
      - All Media - - Product Attachment - - All Products - - Food - - Meat - - All Gender - - 54 - - 51.36 - - 127.83 -
      - All Media - - Product Attachment - - All Products - - Food - - Produce - - All Gender - - 1,069 - - 909.24 - - 2,287.61 -
      - All Media - - Product Attachment - - All Products - - Food - - Seafood - - All Gender - - 45 - - 36.98 - - 100.61 -
      - All Media - - Product Attachment - - All Products - - Food - - Snack Foods - - All Gender - - 819 - - 726.73 - - 1,847.28 -
      - All Media - - Product Attachment - - All Products - - Food - - Snacks - - All Gender - - 209 - - 186.22 - - 450.03 -
      - All Media - - Product Attachment - - All Products - - Food - - Starchy Foods - - All Gender - - 149 - - 126.59 - - 332.47 -
      - All Media - - Product Attachment - - All Products - - Non-Consumable - - All Gender - - 1,390 - - 1,179.48 - - 2,969.35 -
      - All Media - - Product Attachment - - All Products - - Non-Consumable - - Carousel - - All Gender - - 14 - - 7.99 - - 21.21 -
      - All Media - - Product Attachment - - All Products - - Non-Consumable - - Checkout - - All Gender - - 48 - - 40.45 - - 100.61 -
      - All Media - - Product Attachment - - All Products - - Non-Consumable - - Health and Hygiene - - All Gender - - 440 - - 356.54 - - 901.73 -
      - All Media - - Product Attachment - - All Products - - Non-Consumable - - Household - - All Gender - - 777 - - 690.03 - - 1,737.96 -
      - All Media - - Product Attachment - - All Products - - Non-Consumable - - Periodicals - - All Gender - - 111 - - 84.48 - - 207.84 -
      - All Media - - Radio - - All Products - - All Gender - - 2,454 - - 2,087.51 - - 5,213.61 -
      - All Media - - Radio - - All Products - - Drink - - All Gender - - 226 - - 182.85 - - 443.68 -
      - All Media - - Radio - - All Products - - Food - - All Gender - - 1,733 - - 1,485.25 - - 3,727.36 -
      - All Media - - Radio - - All Products - - Food - - Baked Goods - - All Gender - - 83 - - 76.51 - - 186.20 -
      - All Media - - Radio - - All Products - - Food - - Baking Goods - - All Gender - - 157 - - 109.10 - - 274.90 -
      - All Media - - Radio - - All Products - - Food - - Baking Goods - - Baking Goods - - All Gender - - 63 - - 45.02 - - 110.43 -
      - All Media - - Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - All Gender - - 94 - - 64.08 - - 164.47 -
      - All Media - - Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jam - - All Gender - - 15 - - 10.42 - - 26.94 -
      - All Media - - Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jelly - - All Gender - - 24 - - 14.54 - - 37.49 -
      - All Media - - Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - All Gender - - 19 - - 16.85 - - 41.82 -
      - All Media - - Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - All Gender - - 10 - - 10.58 - - 24.44 -
      - All Media - - Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - CDR - - All Gender - -   - -   - -   -
      - All Media - - Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Landslide - - All Gender - -   - -   - -   -
      - All Media - - Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Plato - - All Gender - - 4 - - 3.77 - - 9.80 -
      - All Media - - Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Super - - All Gender - - 5 - - 2.50 - - 7.58 -
      - All Media - - Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Preserves - - All Gender - - 36 - - 22.28 - - 58.22 -
      - All Media - - Radio - - All Products - - Food - - Breakfast Foods - - All Gender - - 25 - - 18.78 - - 50.22 -
      - All Media - - Radio - - All Products - - Food - - Canned Foods - - All Gender - - 158 - - 124.79 - - 307.55 -
      - All Media - - Radio - - All Products - - Food - - Canned Products - - All Gender - - 22 - - 17.29 - - 43.42 -
      - All Media - - Radio - - All Products - - Food - - Dairy - - All Gender - - 112 - - 92.12 - - 216.79 -
      - All Media - - Radio - - All Products - - Food - - Deli - - All Gender - - 129 - - 119.14 - - 307.25 -
      - All Media - - Radio - - All Products - - Food - - Eggs - - All Gender - - 25 - - 29.97 - - 71.15 -
      - All Media - - Radio - - All Products - - Food - - Frozen Foods - - All Gender - - 253 - - 202.71 - - 507.45 -
      - All Media - - Radio - - All Products - - Food - - Meat - - All Gender - - 12 - - 11.53 - - 32.85 -
      - All Media - - Radio - - All Products - - Food - - Produce - - All Gender - - 336 - - 292.05 - - 738.20 -
      - All Media - - Radio - - All Products - - Food - - Seafood - - All Gender - - 15 - - 13.28 - - 35.58 -
      - All Media - - Radio - - All Products - - Food - - Snack Foods - - All Gender - - 290 - - 270.59 - - 674.73 -
      - All Media - - Radio - - All Products - - Food - - Snacks - - All Gender - - 60 - - 55.67 - - 144.58 -
      - All Media - - Radio - - All Products - - Food - - Starchy Foods - - All Gender - - 56 - - 51.72 - - 136.49 -
      - All Media - - Radio - - All Products - - Non-Consumable - - All Gender - - 495 - - 419.41 - - 1,042.57 -
      - All Media - - Radio - - All Products - - Non-Consumable - - Carousel - - All Gender - - 15 - - 11.15 - - 26.85 -
      - All Media - - Radio - - All Products - - Non-Consumable - - Checkout - - All Gender - - 21 - - 17.00 - - 42.74 -
      - All Media - - Radio - - All Products - - Non-Consumable - - Health and Hygiene - - All Gender - - 145 - - 114.84 - - 289.80 -
      - All Media - - Radio - - All Products - - Non-Consumable - - Household - - All Gender - - 258 - - 233.31 - - 575.07 -
      - All Media - - Radio - - All Products - - Non-Consumable - - Periodicals - - All Gender - - 56 - - 43.12 - - 108.11 -
      - All Media - - Street Handout - - All Products - - All Gender - - 5,753 - - 4,856.54 - - 12,192.90 -
      - All Media - - Street Handout - - All Products - - Drink - - All Gender - - 512 - - 372.68 - - 943.42 -
      - All Media - - Street Handout - - All Products - - Food - - All Gender - - 4,239 - - 3,650.32 - - 9,151.65 -
      - All Media - - Street Handout - - All Products - - Food - - Baked Goods - - All Gender - - 160 - - 120.12 - - 301.62 -
      - All Media - - Street Handout - - All Products - - Food - - Baking Goods - - All Gender - - 498 - - 373.67 - - 923.22 -
      - All Media - - Street Handout - - All Products - - Food - - Baking Goods - - Baking Goods - - All Gender - - 200 - - 144.16 - - 357.82 -
      - All Media - - Street Handout - - All Products - - Food - - Baking Goods - - Jams and Jellies - - All Gender - - 298 - - 229.51 - - 565.40 -
      - All Media - - Street Handout - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jam - - All Gender - - 53 - - 44.30 - - 112.95 -
      - All Media - - Street Handout - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jelly - - All Gender - - 92 - - 63.14 - - 155.59 -
      - All Media - - Street Handout - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - All Gender - - 51 - - 51.06 - - 118.90 -
      - All Media - - Street Handout - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - All Gender - - 11 - - 10.85 - - 25.72 -
      - All Media - - Street Handout - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - CDR - - All Gender - - 8 - - 9.06 - - 19.73 -
      - All Media - - Street Handout - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Landslide - - All Gender - - 11 - - 6.90 - - 15.54 -
      - All Media - - Street Handout - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Plato - - All Gender - - 9 - - 8.47 - - 20.89 -
      - All Media - - Street Handout - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Super - - All Gender - - 12 - - 15.78 - - 37.02 -
      - All Media - - Street Handout - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Preserves - - All Gender - - 102 - - 71.02 - - 177.96 -
      - All Media - - Street Handout - - All Products - - Food - - Breakfast Foods - - All Gender - - 81 - - 74.32 - - 192.90 -
      - All Media - - Street Handout - - All Products - - Food - - Canned Foods - - All Gender - - 459 - - 413.21 - - 1,021.86 -
      - All Media - - Street Handout - - All Products - - Food - - Canned Products - - All Gender - - 30 - - 19.43 - - 45.68 -
      - All Media - - Street Handout - - All Products - - Food - - Dairy - - All Gender - - 301 - - 285.98 - - 718.61 -
      - All Media - - Street Handout - - All Products - - Food - - Deli - - All Gender - - 305 - - 253.54 - - 638.30 -
      - All Media - - Street Handout - - All Products - - Food - - Eggs - - All Gender - - 66 - - 59.15 - - 156.82 -
      - All Media - - Street Handout - - All Products - - Food - - Frozen Foods - - All Gender - - 612 - - 520.12 - - 1,313.71 -
      - All Media - - Street Handout - - All Products - - Food - - Meat - - All Gender - - 37 - - 29.82 - - 78.24 -
      - All Media - - Street Handout - - All Products - - Food - - Produce - - All Gender - - 745 - - 662.39 - - 1,639.94 -
      - All Media - - Street Handout - - All Products - - Food - - Seafood - - All Gender - - 37 - - 30.12 - - 72.77 -
      - All Media - - Street Handout - - All Products - - Food - - Snack Foods - - All Gender - - 675 - - 600.23 - - 1,515.68 -
      - All Media - - Street Handout - - All Products - - Food - - Snacks - - All Gender - - 144 - - 128.79 - - 321.16 -
      - All Media - - Street Handout - - All Products - - Food - - Starchy Foods - - All Gender - - 89 - - 79.43 - - 211.14 -
      - All Media - - Street Handout - - All Products - - Non-Consumable - - All Gender - - 1,002 - - 833.53 - - 2,097.83 -
      - All Media - - Street Handout - - All Products - - Non-Consumable - - Carousel - - All Gender - - 17 - - 13.53 - - 30.98 -
      - All Media - - Street Handout - - All Products - - Non-Consumable - - Checkout - - All Gender - - 45 - - 34.77 - - 85.38 -
      - All Media - - Street Handout - - All Products - - Non-Consumable - - Health and Hygiene - - All Gender - - 402 - - 318.03 - - 802.92 -
      - All Media - - Street Handout - - All Products - - Non-Consumable - - Household - - All Gender - - 501 - - 436.41 - - 1,105.38 -
      - All Media - - Street Handout - - All Products - - Non-Consumable - - Periodicals - - All Gender - - 37 - - 30.80 - - 73.17 -
      - All Media - - Sunday Paper - - All Products - - All Gender - - 4,339 - - 3,673.86 - - 9,092.89 -
      - All Media - - Sunday Paper - - All Products - - Drink - - All Gender - - 430 - - 345.53 - - 856.73 -
      - All Media - - Sunday Paper - - All Products - - Food - - All Gender - - 3,106 - - 2,646.47 - - 6,559.46 -
      - All Media - - Sunday Paper - - All Products - - Food - - Baked Goods - - All Gender - - 140 - - 110.79 - - 282.55 -
      - All Media - - Sunday Paper - - All Products - - Food - - Baking Goods - - All Gender - - 338 - - 239.76 - - 603.86 -
      - All Media - - Sunday Paper - - All Products - - Food - - Baking Goods - - Baking Goods - - All Gender - - 170 - - 118.05 - - 298.79 -
      - All Media - - Sunday Paper - - All Products - - Food - - Baking Goods - - Jams and Jellies - - All Gender - - 168 - - 121.71 - - 305.07 -
      - All Media - - Sunday Paper - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jam - - All Gender - - 24 - - 22.35 - - 54.83 -
      - All Media - - Sunday Paper - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jelly - - All Gender - - 27 - - 18.20 - - 47.12 -
      - All Media - - Sunday Paper - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - All Gender - - 51 - - 37.67 - - 96.67 -
      - All Media - - Sunday Paper - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - All Gender - - 10 - - 6.08 - - 16.22 -
      - All Media - - Sunday Paper - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - CDR - - All Gender - - 10 - - 10.47 - - 26.50 -
      - All Media - - Sunday Paper - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Landslide - - All Gender - - 15 - - 6.20 - - 16.31 -
      - All Media - - Sunday Paper - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Plato - - All Gender - - 16 - - 14.93 - - 37.64 -
      - All Media - - Sunday Paper - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Super - - All Gender - -   - -   - -   -
      - All Media - - Sunday Paper - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Preserves - - All Gender - - 66 - - 43.49 - - 106.45 -
      - All Media - - Sunday Paper - - All Products - - Food - - Breakfast Foods - - All Gender - - 55 - - 49.80 - - 120.23 -
      - All Media - - Sunday Paper - - All Products - - Food - - Canned Foods - - All Gender - - 283 - - 249.46 - - 605.11 -
      - All Media - - Sunday Paper - - All Products - - Food - - Canned Products - - All Gender - - 34 - - 29.65 - - 72.18 -
      - All Media - - Sunday Paper - - All Products - - Food - - Dairy - - All Gender - - 200 - - 201.94 - - 497.91 -
      - All Media - - Sunday Paper - - All Products - - Food - - Deli - - All Gender - - 228 - - 188.37 - - 467.53 -
      - All Media - - Sunday Paper - - All Products - - Food - - Eggs - - All Gender - - 54 - - 47.68 - - 118.44 -
      - All Media - - Sunday Paper - - All Products - - Food - - Frozen Foods - - All Gender - - 425 - - 330.81 - - 839.15 -
      - All Media - - Sunday Paper - - All Products - - Food - - Meat - - All Gender - - 18 - - 19.85 - - 52.20 -
      - All Media - - Sunday Paper - - All Products - - Food - - Produce - - All Gender - - 603 - - 520.95 - - 1,274.70 -
      - All Media - - Sunday Paper - - All Products - - Food - - Seafood - - All Gender - - 27 - - 26.82 - - 69.49 -
      - All Media - - Sunday Paper - - All Products - - Food - - Snack Foods - - All Gender - - 469 - - 413.18 - - 1,027.98 -
      - All Media - - Sunday Paper - - All Products - - Food - - Snacks - - All Gender - - 123 - - 108.50 - - 261.38 -
      - All Media - - Sunday Paper - - All Products - - Food - - Starchy Foods - - All Gender - - 109 - - 108.91 - - 266.75 -
      - All Media - - Sunday Paper - - All Products - - Non-Consumable - - All Gender - - 803 - - 681.86 - - 1,676.70 -
      - All Media - - Sunday Paper - - All Products - - Non-Consumable - - Carousel - - All Gender - - 7 - - 6.70 - - 14.68 -
      - All Media - - Sunday Paper - - All Products - - Non-Consumable - - Checkout - - All Gender - - 17 - - 13.09 - - 30.89 -
      - All Media - - Sunday Paper - - All Products - - Non-Consumable - - Health and Hygiene - - All Gender - - 278 - - 227.06 - - 565.99 -
      - All Media - - Sunday Paper - - All Products - - Non-Consumable - - Household - - All Gender - - 420 - - 371.58 - - 911.69 -
      - All Media - - Sunday Paper - - All Products - - Non-Consumable - - Periodicals - - All Gender - - 81 - - 63.43 - - 153.45 -
      - All Media - - Sunday Paper, Radio - - All Products - - All Gender - - 5,945 - - 5,027.31 - - 12,551.96 -
      - All Media - - Sunday Paper, Radio - - All Products - - Drink - - All Gender - - 591 - - 454.03 - - 1,129.94 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - All Gender - - 4,239 - - 3,612.38 - - 9,033.23 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Baked Goods - - All Gender - - 152 - - 109.11 - - 274.39 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Baking Goods - - All Gender - - 482 - - 367.13 - - 913.84 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Baking Goods - - Baking Goods - - All Gender - - 206 - - 152.72 - - 381.59 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - All Gender - - 276 - - 214.41 - - 532.25 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jam - - All Gender - - 52 - - 52.39 - - 126.62 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jelly - - All Gender - - 74 - - 53.93 - - 135.03 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - All Gender - - 64 - - 50.10 - - 126.71 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - All Gender - - 14 - - 11.58 - - 27.40 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - CDR - - All Gender - - 17 - - 14.68 - - 41.25 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Landslide - - All Gender - - 14 - - 6.62 - - 17.04 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Plato - - All Gender - - 7 - - 6.91 - - 17.15 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Super - - All Gender - - 12 - - 10.31 - - 23.87 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Preserves - - All Gender - - 86 - - 57.99 - - 143.89 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Breakfast Foods - - All Gender - - 80 - - 62.80 - - 154.04 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Canned Foods - - All Gender - - 456 - - 361.79 - - 914.81 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Canned Products - - All Gender - - 45 - - 39.72 - - 95.88 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Dairy - - All Gender - - 283 - - 296.91 - - 722.75 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Deli - - All Gender - - 252 - - 190.32 - - 479.59 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Eggs - - All Gender - - 114 - - 104.65 - - 256.15 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Frozen Foods - - All Gender - - 599 - - 490.33 - - 1,222.54 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Meat - - All Gender - - 40 - - 31.66 - - 84.76 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Produce - - All Gender - - 858 - - 752.62 - - 1,886.01 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Seafood - - All Gender - - 27 - - 20.66 - - 50.39 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Snack Foods - - All Gender - - 596 - - 555.70 - - 1,402.21 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Snacks - - All Gender - - 147 - - 120.43 - - 304.18 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Starchy Foods - - All Gender - - 108 - - 108.55 - - 271.69 -
      - All Media - - Sunday Paper, Radio - - All Products - - Non-Consumable - - All Gender - - 1,115 - - 960.90 - - 2,388.79 -
      - All Media - - Sunday Paper, Radio - - All Products - - Non-Consumable - - Carousel - - All Gender - - 18 - - 10.99 - - 26.94 -
      - All Media - - Sunday Paper, Radio - - All Products - - Non-Consumable - - Checkout - - All Gender - - 26 - - 24.68 - - 62.14 -
      - All Media - - Sunday Paper, Radio - - All Products - - Non-Consumable - - Health and Hygiene - - All Gender - - 378 - - 309.37 - - 771.48 -
      - All Media - - Sunday Paper, Radio - - All Products - - Non-Consumable - - Household - - All Gender - - 585 - - 516.99 - - 1,276.16 -
      - All Media - - Sunday Paper, Radio - - All Products - - Non-Consumable - - Periodicals - - All Gender - - 108 - - 98.86 - - 252.07 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - All Gender - - 2,726 - - 2,341.58 - - 5,819.33 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Drink - - All Gender - - 225 - - 163.09 - - 403.51 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - All Gender - - 2,021 - - 1,762.18 - - 4,377.85 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Baked Goods - - All Gender - - 67 - - 66.17 - - 163.29 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Baking Goods - - All Gender - - 228 - - 182.98 - - 455.90 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Baking Goods - - Baking Goods - - All Gender - - 90 - - 73.09 - - 176.63 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - All Gender - - 138 - - 109.90 - - 279.27 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jam - - All Gender - - 37 - - 31.30 - - 78.56 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jelly - - All Gender - - 27 - - 16.18 - - 39.92 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - All Gender - - 30 - - 24.01 - - 64.19 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - All Gender - - 11 - - 9.78 - - 23.86 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - CDR - - All Gender - -   - -   - -   -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Landslide - - All Gender - - 4 - - 2.39 - - 5.68 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Plato - - All Gender - - 5 - - 3.85 - - 11.60 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Super - - All Gender - - 10 - - 7.99 - - 23.05 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Preserves - - All Gender - - 44 - - 38.41 - - 96.60 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Breakfast Foods - - All Gender - - 38 - - 32.76 - - 89.85 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Canned Foods - - All Gender - - 180 - - 138.77 - - 340.04 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Canned Products - - All Gender - - 14 - - 12.00 - - 28.28 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Dairy - - All Gender - - 121 - - 125.32 - - 305.43 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Deli - - All Gender - - 131 - - 98.93 - - 245.42 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Eggs - - All Gender - - 39 - - 39.57 - - 91.99 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Frozen Foods - - All Gender - - 279 - - 207.59 - - 514.95 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Meat - - All Gender - - 12 - - 11.77 - - 30.23 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Produce - - All Gender - - 411 - - 382.14 - - 943.93 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Seafood - - All Gender - - 31 - - 28.07 - - 69.82 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Snack Foods - - All Gender - - 346 - - 318.26 - - 798.50 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Snacks - - All Gender - - 75 - - 65.49 - - 174.02 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Starchy Foods - - All Gender - - 49 - - 52.37 - - 126.20 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Non-Consumable - - All Gender - - 480 - - 416.30 - - 1,037.97 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Non-Consumable - - Carousel - - All Gender - - 21 - - 11.63 - - 27.92 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Non-Consumable - - Checkout - - All Gender - - 10 - - 8.12 - - 19.80 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Non-Consumable - - Health and Hygiene - - All Gender - - 138 - - 110.35 - - 276.31 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Non-Consumable - - Household - - All Gender - - 262 - - 244.90 - - 608.52 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Non-Consumable - - Periodicals - - All Gender - - 49 - - 41.30 - - 105.42 -
      - All Media - - TV - - All Products - - All Gender - - 3,607 - - 3,116.40 - - 7,786.21 -
      - All Media - - TV - - All Products - - Drink - - All Gender - - 332 - - 283.18 - - 721.07 -
      - All Media - - TV - - All Products - - Food - - All Gender - - 2,563 - - 2,238.13 - - 5,573.27 -
      - All Media - - TV - - All Products - - Food - - Baked Goods - - All Gender - - 114 - - 103.40 - - 262.97 -
      - All Media - - TV - - All Products - - Food - - Baking Goods - - All Gender - - 237 - - 185.55 - - 464.23 -
      - All Media - - TV - - All Products - - Food - - Baking Goods - - Baking Goods - - All Gender - - 95 - - 74.29 - - 190.59 -
      - All Media - - TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - All Gender - - 142 - - 111.25 - - 273.64 -
      - All Media - - TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jam - - All Gender - - 38 - - 32.28 - - 77.58 -
      - All Media - - TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jelly - - All Gender - - 35 - - 24.64 - - 63.38 -
      - All Media - - TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - All Gender - - 31 - - 21.83 - - 56.80 -
      - All Media - - TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - All Gender - -   - -   - -   -
      - All Media - - TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - CDR - - All Gender - - 11 - - 9.78 - - 27.19 -
      - All Media - - TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Landslide - - All Gender - - 7 - - 2.61 - - 7.12 -
      - All Media - - TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Plato - - All Gender - - 6 - - 4.95 - - 12.13 -
      - All Media - - TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Super - - All Gender - - 7 - - 4.48 - - 10.36 -
      - All Media - - TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Preserves - - All Gender - - 38 - - 32.51 - - 75.88 -
      - All Media - - TV - - All Products - - Food - - Breakfast Foods - - All Gender - - 36 - - 30.11 - - 79.89 -
      - All Media - - TV - - All Products - - Food - - Canned Foods - - All Gender - - 240 - - 200.00 - - 519.91 -
      - All Media - - TV - - All Products - - Food - - Canned Products - - All Gender - - 26 - - 15.00 - - 38.65 -
      - All Media - - TV - - All Products - - Food - - Dairy - - All Gender - - 179 - - 183.73 - - 458.87 -
      - All Media - - TV - - All Products - - Food - - Deli - - All Gender - - 155 - - 139.76 - - 342.51 -
      - All Media - - TV - - All Products - - Food - - Eggs - - All Gender - - 42 - - 32.74 - - 80.93 -
      - All Media - - TV - - All Products - - Food - - Frozen Foods - - All Gender - - 352 - - 300.42 - - 738.40 -
      - All Media - - TV - - All Products - - Food - - Meat - - All Gender - - 22 - - 19.76 - - 49.27 -
      - All Media - - TV - - All Products - - Food - - Produce - - All Gender - - 543 - - 456.53 - - 1,145.45 -
      - All Media - - TV - - All Products - - Food - - Seafood - - All Gender - - 34 - - 30.71 - - 75.47 -
      - All Media - - TV - - All Products - - Food - - Snack Foods - - All Gender - - 401 - - 377.01 - - 927.50 -
      - All Media - - TV - - All Products - - Food - - Snacks - - All Gender - - 99 - - 92.80 - - 220.54 -
      - All Media - - TV - - All Products - - Food - - Starchy Foods - - All Gender - - 83 - - 70.61 - - 168.68 -
      - All Media - - TV - - All Products - - Non-Consumable - - All Gender - - 712 - - 595.08 - - 1,491.87 -
      - All Media - - TV - - All Products - - Non-Consumable - - Carousel - - All Gender - - 4 - - 3.13 - - 9.20 -
      - All Media - - TV - - All Products - - Non-Consumable - - Checkout - - All Gender - - 34 - - 34.12 - - 86.21 -
      - All Media - - TV - - All Products - - Non-Consumable - - Health and Hygiene - - All Gender - - 249 - - 196.08 - - 486.46 -
      - All Media - - TV - - All Products - - Non-Consumable - - Household - - All Gender - - 361 - - 316.09 - - 795.40 -
      - All Media - - TV - - All Products - - Non-Consumable - - Periodicals - - All Gender - - 64 - - 45.67 - - 114.60 -
      +   + + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + All Products + + All Gender + + 266,773 + + 225,627.23 + + 565,238.13 +
      + All Media + + All Products + + Drink + + All Gender + + 24,597 + + 19,477.23 + + 48,836.21 +
      + All Media + + All Products + + Food + + All Gender + + 191,940 + + 163,270.72 + + 409,035.59 +
      + All Media + + All Products + + Food + + Baked Goods + + All Gender + + 7,870 + + 6,564.09 + + 16,455.43 +
      + All Media + + All Products + + Food + + Baking Goods + + All Gender + + 20,245 + + 15,370.61 + + 38,670.41 +
      + All Media + + All Products + + Food + + Baking Goods + + Baking Goods + + All Gender + + 8,357 + + 6,123.32 + + 15,446.69 +
      + All Media + + All Products + + Food + + Baking Goods + + Baking Goods + + All Gender + + F + + 4,005 + + 2,907.70 + + 7,313.61 +
      + All Media + + All Products + + Food + + Baking Goods + + Baking Goods + + All Gender + + M + + 4,352 + + 3,215.62 + + 8,133.08 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + All Gender + + 11,888 + + 9,247.29 + + 23,223.72 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jam + + All Gender + + 2,556 + + 2,132.27 + + 5,401.81 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jelly + + All Gender + + 2,565 + + 1,830.04 + + 4,609.61 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jelly + + All Gender + + F + + 1,309 + + 956.94 + + 2,414.94 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jelly + + All Gender + + M + + 1,256 + + 873.10 + + 2,194.67 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + All Gender + + 2,667 + + 2,097.37 + + 5,231.08 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + All Gender + + 556 + + 424.38 + + 1,055.72 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + All Gender + + F + + 271 + + 201.08 + + 500.39 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + All Gender + + M + + 285 + + 223.30 + + 555.33 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + BBB Best Chunky Peanut Butter + + All Gender + + 188 + + 147.32 + + 370.36 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + BBB Best Chunky Peanut Butter + + All Gender + + F + + 107 + + 85.81 + + 210.79 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + BBB Best Chunky Peanut Butter + + All Gender + + M + + 81 + + 61.50 + + 159.57 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + BBB Best Creamy Peanut Butter + + All Gender + + 201 + + 87.86 + + 221.10 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + BBB Best Creamy Peanut Butter + + All Gender + + F + + 99 + + 43.35 + + 108.90 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + BBB Best Creamy Peanut Butter + + All Gender + + M + + 102 + + 44.51 + + 112.20 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + BBB Best Extra Chunky Peanut Butter + + All Gender + + 167 + + 189.21 + + 464.26 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + BBB Best Extra Chunky Peanut Butter + + All Gender + + F + + 65 + + 71.92 + + 180.70 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + BBB Best Extra Chunky Peanut Butter + + All Gender + + M + + 102 + + 117.29 + + 283.56 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + CDR + + All Gender + + 545 + + 538.88 + + 1,326.30 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Landslide + + All Gender + + 531 + + 256.16 + + 635.29 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Plato + + All Gender + + 520 + + 447.73 + + 1,132.16 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Super + + All Gender + + 515 + + 430.21 + + 1,081.61 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Preserves + + All Gender + + 4,100 + + 3,187.61 + + 7,981.22 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Preserves + + All Gender + + F + + 1,946 + + 1,472.42 + + 3,717.80 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Preserves + + All Gender + + M + + 2,154 + + 1,715.19 + + 4,263.42 +
      + All Media + + All Products + + Food + + Breakfast Foods + + All Gender + + 3,317 + + 2,756.80 + + 6,941.46 +
      + All Media + + All Products + + Food + + Canned Foods + + All Gender + + 19,026 + + 15,894.53 + + 39,774.34 +
      + All Media + + All Products + + Food + + Canned Foods + + Canned Anchovies + + All Gender + + 900 + + 913.88 + + 2,296.38 +
      + All Media + + All Products + + Food + + Canned Foods + + Canned Clams + + All Gender + + 882 + + 759.80 + + 1,912.68 +
      + All Media + + All Products + + Food + + Canned Foods + + Canned Clams + + Clams + + All Gender + + 882 + + 759.80 + + 1,912.68 +
      + All Media + + All Products + + Food + + Canned Foods + + Canned Clams + + Clams + + Better + + All Gender + + 189 + + 151.14 + + 398.79 +
      + All Media + + All Products + + Food + + Canned Foods + + Canned Clams + + Clams + + Blue Label + + All Gender + + 165 + + 112.82 + + 278.85 +
      + All Media + + All Products + + Food + + Canned Foods + + Canned Clams + + Clams + + Bravo + + All Gender + + 184 + + 280.70 + + 708.40 +
      + All Media + + All Products + + Food + + Canned Foods + + Canned Clams + + Clams + + Just Right + + All Gender + + 177 + + 161.96 + + 394.71 +
      + All Media + + All Products + + Food + + Canned Foods + + Canned Clams + + Clams + + Pleasant + + All Gender + + 167 + + 53.17 + + 131.93 +
      + All Media + + All Products + + Food + + Canned Foods + + Canned Oysters + + All Gender + + 708 + + 571.50 + + 1,442.77 +
      + All Media + + All Products + + Food + + Canned Foods + + Canned Sardines + + All Gender + + 819 + + 537.59 + + 1,357.80 +
      + All Media + + All Products + + Food + + Canned Foods + + Canned Shrimp + + All Gender + + 804 + + 858.39 + + 2,146.49 +
      + All Media + + All Products + + Food + + Canned Foods + + Canned Soup + + All Gender + + 8,006 + + 6,408.29 + + 15,966.10 +
      + All Media + + All Products + + Food + + Canned Foods + + Canned Tuna + + All Gender + + 1,710 + + 1,288.52 + + 3,210.76 +
      + All Media + + All Products + + Food + + Canned Foods + + Vegetables + + All Gender + + 5,197 + + 4,556.57 + + 11,441.36 +
      + All Media + + All Products + + Food + + Canned Products + + All Gender + + 1,812 + + 1,317.13 + + 3,314.52 +
      + All Media + + All Products + + Food + + Dairy + + All Gender + + 12,885 + + 12,228.85 + + 30,508.85 +
      + All Media + + All Products + + Food + + Deli + + All Gender + + 12,037 + + 10,108.87 + + 25,318.93 +
      + All Media + + All Products + + Food + + Deli + + Meat + + All Gender + + 9,433 + + 8,215.81 + + 20,616.29 +
      + All Media + + All Products + + Food + + Deli + + Meat + + Bologna + + All Gender + + 2,588 + + 2,340.24 + + 5,859.95 +
      + All Media + + All Products + + Food + + Deli + + Meat + + Deli Meats + + All Gender + + 3,339 + + 2,851.18 + + 7,191.24 +
      + All Media + + All Products + + Food + + Deli + + Meat + + Deli Meats + + All Gender + + F + + 1,653 + + 1,414.49 + + 3,579.34 +
      + All Media + + All Products + + Food + + Deli + + Meat + + Deli Meats + + All Gender + + M + + 1,686 + + 1,436.69 + + 3,611.90 +
      + All Media + + All Products + + Food + + Deli + + Meat + + Fresh Chicken + + All Gender + + 878 + + 842.85 + + 2,091.52 +
      + All Media + + All Products + + Food + + Deli + + Meat + + Hot Dogs + + All Gender + + 2,628 + + 2,181.55 + + 5,473.58 +
      + All Media + + All Products + + Food + + Deli + + Side Dishes + + All Gender + + 2,604 + + 1,893.06 + + 4,702.64 +
      + All Media + + All Products + + Food + + Eggs + + All Gender + + 4,132 + + 3,684.90 + + 9,200.76 +
      + All Media + + All Products + + Food + + Frozen Foods + + All Gender + + 26,655 + + 22,030.66 + + 55,207.50 +
      + All Media + + All Products + + Food + + Meat + + All Gender + + 1,714 + + 1,465.42 + + 3,669.89 +
      + All Media + + All Products + + Food + + Produce + + All Gender + + 37,792 + + 32,831.33 + + 82,248.42 +
      + All Media + + All Products + + Food + + Seafood + + All Gender + + 1,764 + + 1,520.70 + + 3,809.14 +
      + All Media + + All Products + + Food + + Snack Foods + + All Gender + + 30,545 + + 26,963.34 + + 67,609.82 +
      + All Media + + All Products + + Food + + Snacks + + All Gender + + 6,884 + + 5,827.58 + + 14,550.05 +
      + All Media + + All Products + + Food + + Starchy Foods + + All Gender + + 5,262 + + 4,705.91 + + 11,756.07 +
      + All Media + + All Products + + Non-Consumable + + All Gender + + 50,236 + + 42,879.28 + + 107,366.33 +
      + All Media + + All Products + + Non-Consumable + + Carousel + + All Gender + + 841 + + 595.97 + + 1,500.11 +
      + All Media + + All Products + + Non-Consumable + + Checkout + + All Gender + + 1,779 + + 1,525.04 + + 3,767.71 +
      + All Media + + All Products + + Non-Consumable + + Health and Hygiene + + All Gender + + 16,284 + + 12,972.99 + + 32,571.86 +
      + All Media + + All Products + + Non-Consumable + + Household + + All Gender + + 27,038 + + 24,170.73 + + 60,469.89 +
      + All Media + + All Products + + Non-Consumable + + Periodicals + + All Gender + + 4,294 + + 3,614.55 + + 9,056.76 +
      + All Media + + Bulk Mail + + All Products + + All Gender + + 4,320 + + 3,740.95 + + 9,349.07 +
      + All Media + + Cash Register Handout + + All Products + + All Gender + + 6,697 + + 5,715.67 + + 14,321.33 +
      + All Media + + Daily Paper + + All Products + + All Gender + + 7,738 + + 6,559.23 + + 16,479.81 +
      + All Media + + Daily Paper, Radio + + All Products + + All Gender + + 6,891 + + 5,668.77 + + 14,169.42 +
      + All Media + + Daily Paper, Radio, TV + + All Products + + All Gender + + 9,513 + + 8,055.22 + + 20,173.97 +
      + All Media + + In-Store Coupon + + All Products + + All Gender + + 3,798 + + 3,263.11 + + 8,162.46 +
      + All Media + + In-Store Coupon + + All Products + + Drink + + All Gender + + 345 + + 282.44 + + 708.38 +
      + All Media + + In-Store Coupon + + All Products + + Food + + All Gender + + 2,737 + + 2,345.57 + + 5,889.34 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Baked Goods + + All Gender + + 131 + + 114.11 + + 279.11 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Baking Goods + + All Gender + + 308 + + 252.88 + + 632.01 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Baking Goods + + Baking Goods + + All Gender + + 146 + + 103.30 + + 261.44 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Baking Goods + + Jams and Jellies + + All Gender + + 162 + + 149.58 + + 370.57 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jam + + All Gender + + 55 + + 58.16 + + 141.19 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jelly + + All Gender + + 32 + + 23.96 + + 62.12 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + All Gender + + 22 + + 19.54 + + 48.72 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + All Gender + + 7 + + 6.72 + + 16.10 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + CDR + + All Gender + + 10 + + 9.81 + + 24.32 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Landslide + + All Gender + +   + +   + +   +
      + All Media + + In-Store Coupon + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Plato + + All Gender + + 3 + + 2.32 + + 6.32 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Super + + All Gender + + 2 + + .69 + + 1.98 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Preserves + + All Gender + + 53 + + 47.92 + + 118.54 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Breakfast Foods + + All Gender + + 59 + + 49.22 + + 125.19 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Breakfast Foods + + All Gender + + F + + 33 + + 22.88 + + 54.84 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Breakfast Foods + + All Gender + + M + + 26 + + 26.34 + + 70.35 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Canned Foods + + All Gender + + 245 + + 200.61 + + 506.67 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Canned Products + + All Gender + + 15 + + 9.58 + + 26.17 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Dairy + + All Gender + + 166 + + 153.42 + + 372.01 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Deli + + All Gender + + 180 + + 163.58 + + 392.68 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Eggs + + All Gender + + 56 + + 42.51 + + 108.90 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Frozen Foods + + All Gender + + 374 + + 301.63 + + 773.52 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Meat + + All Gender + + 31 + + 23.91 + + 70.35 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Produce + + All Gender + + 563 + + 499.63 + + 1,257.05 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Seafood + + All Gender + + 34 + + 30.06 + + 76.09 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Snack Foods + + All Gender + + 439 + + 390.35 + + 989.13 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Snacks + + All Gender + + 78 + + 63.77 + + 153.02 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Starchy Foods + + All Gender + + 58 + + 50.30 + + 127.44 +
      + All Media + + In-Store Coupon + + All Products + + Non-Consumable + + All Gender + + 716 + + 635.10 + + 1,564.74 +
      + All Media + + In-Store Coupon + + All Products + + Non-Consumable + + Carousel + + All Gender + + 17 + + 8.77 + + 24.18 +
      + All Media + + In-Store Coupon + + All Products + + Non-Consumable + + Checkout + + All Gender + + 23 + + 15.20 + + 40.19 +
      + All Media + + In-Store Coupon + + All Products + + Non-Consumable + + Health and Hygiene + + All Gender + + 251 + + 193.53 + + 477.21 +
      + All Media + + In-Store Coupon + + All Products + + Non-Consumable + + Household + + All Gender + + 374 + + 375.66 + + 916.97 +
      + All Media + + In-Store Coupon + + All Products + + Non-Consumable + + Periodicals + + All Gender + + 51 + + 41.94 + + 106.19 +
      + All Media + + No Media + + All Products + + All Gender + + 195,448 + + 165,214.85 + + 414,026.92 +
      + All Media + + No Media + + All Products + + Drink + + All Gender + + 17,896 + + 14,211.41 + + 35,681.85 +
      + All Media + + No Media + + All Products + + Food + + All Gender + + 140,577 + + 119,469.36 + + 299,356.11 +
      + All Media + + No Media + + All Products + + Food + + Baked Goods + + All Gender + + 5,753 + + 4,775.86 + + 11,972.46 +
      + All Media + + No Media + + All Products + + Food + + Baking Goods + + All Gender + + 14,849 + + 11,226.15 + + 28,312.78 +
      + All Media + + No Media + + All Products + + Food + + Baking Goods + + Baking Goods + + All Gender + + 5,979 + + 4,347.34 + + 11,002.73 +
      + All Media + + No Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + All Gender + + 8,870 + + 6,878.81 + + 17,310.05 +
      + All Media + + No Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jam + + All Gender + + 1,883 + + 1,554.13 + + 3,965.74 +
      + All Media + + No Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jelly + + All Gender + + 1,936 + + 1,394.32 + + 3,504.71 +
      + All Media + + No Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + All Gender + + 1,984 + + 1,534.19 + + 3,828.01 +
      + All Media + + No Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + All Gender + + 406 + + 293.97 + + 735.29 +
      + All Media + + No Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + CDR + + All Gender + + 411 + + 401.88 + + 998.12 +
      + All Media + + No Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Landslide + + All Gender + + 401 + + 195.51 + + 478.44 +
      + All Media + + No Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Plato + + All Gender + + 384 + + 331.26 + + 832.92 +
      + All Media + + No Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Super + + All Gender + + 382 + + 311.57 + + 783.24 +
      + All Media + + No Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Preserves + + All Gender + + 3,067 + + 2,396.16 + + 6,011.59 +
      + All Media + + No Media + + All Products + + Food + + Breakfast Foods + + All Gender + + 2,418 + + 1,996.45 + + 5,016.10 +
      + All Media + + No Media + + All Products + + Food + + Canned Foods + + All Gender + + 13,861 + + 11,647.47 + + 29,102.79 +
      + All Media + + No Media + + All Products + + Food + + Canned Products + + All Gender + + 1,344 + + 960.82 + + 2,424.98 +
      + All Media + + No Media + + All Products + + Food + + Dairy + + All Gender + + 9,510 + + 8,981.13 + + 22,454.02 +
      + All Media + + No Media + + All Products + + Food + + Deli + + All Gender + + 8,695 + + 7,353.56 + + 18,410.26 +
      + All Media + + No Media + + All Products + + Food + + Eggs + + All Gender + + 2,976 + + 2,640.47 + + 6,606.25 +
      + All Media + + No Media + + All Products + + Food + + Frozen Foods + + All Gender + + 19,450 + + 16,127.24 + + 40,411.08 +
      + All Media + + No Media + + All Products + + Food + + Meat + + All Gender + + 1,236 + + 1,068.07 + + 2,646.00 +
      + All Media + + No Media + + All Products + + Food + + Produce + + All Gender + + 27,637 + + 24,036.36 + + 60,203.58 +
      + All Media + + No Media + + All Products + + Food + + Seafood + + All Gender + + 1,292 + + 1,114.69 + + 2,774.43 +
      + All Media + + No Media + + All Products + + Food + + Snack Foods + + All Gender + + 22,525 + + 19,800.82 + + 49,680.71 +
      + All Media + + No Media + + All Products + + Food + + Snacks + + All Gender + + 5,100 + + 4,264.55 + + 10,690.26 +
      + All Media + + No Media + + All Products + + Food + + Starchy Foods + + All Gender + + 3,931 + + 3,475.74 + + 8,650.41 +
      + All Media + + No Media + + All Products + + Non-Consumable + + All Gender + + 36,975 + + 31,534.08 + + 78,988.96 +
      + All Media + + No Media + + All Products + + Non-Consumable + + Carousel + + All Gender + + 584 + + 419.65 + + 1,050.75 +
      + All Media + + No Media + + All Products + + Non-Consumable + + Checkout + + All Gender + + 1,305 + + 1,113.97 + + 2,768.66 +
      + All Media + + No Media + + All Products + + Non-Consumable + + Health and Hygiene + + All Gender + + 11,845 + + 9,413.25 + + 23,621.12 +
      + All Media + + No Media + + All Products + + Non-Consumable + + Household + + All Gender + + 20,091 + + 17,929.20 + + 44,881.13 +
      + All Media + + No Media + + All Products + + Non-Consumable + + Periodicals + + All Gender + + 3,150 + + 2,658.00 + + 6,667.30 +
      + All Media + + Product Attachment + + All Products + + All Gender + + 7,544 + + 6,306.24 + + 15,898.25 +
      + All Media + + Product Attachment + + All Products + + Drink + + All Gender + + 713 + + 555.05 + + 1,403.65 +
      + All Media + + Product Attachment + + All Products + + Food + + All Gender + + 5,441 + + 4,571.71 + + 11,525.25 +
      + All Media + + Product Attachment + + All Products + + Food + + Baked Goods + + All Gender + + 213 + + 175.69 + + 445.60 +
      + All Media + + Product Attachment + + All Products + + Food + + Baking Goods + + All Gender + + 547 + + 410.31 + + 1,032.59 +
      + All Media + + Product Attachment + + All Products + + Food + + Baking Goods + + Baking Goods + + All Gender + + 258 + + 191.48 + + 470.58 +
      + All Media + + Product Attachment + + All Products + + Food + + Baking Goods + + Jams and Jellies + + All Gender + + 289 + + 218.83 + + 562.01 +
      + All Media + + Product Attachment + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jam + + All Gender + + 66 + + 48.03 + + 128.68 +
      + All Media + + Product Attachment + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jelly + + All Gender + + 45 + + 34.12 + + 90.62 +
      + All Media + + Product Attachment + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + All Gender + + 63 + + 47.71 + + 122.31 +
      + All Media + + Product Attachment + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + All Gender + + 15 + + 14.53 + + 38.46 +
      + All Media + + Product Attachment + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + CDR + + All Gender + + 13 + + 11.94 + + 30.57 +
      + All Media + + Product Attachment + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Landslide + + All Gender + + 12 + + 5.32 + + 14.28 +
      + All Media + + Product Attachment + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Plato + + All Gender + + 9 + + 7.16 + + 17.43 +
      + All Media + + Product Attachment + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Super + + All Gender + + 14 + + 8.75 + + 21.57 +
      + All Media + + Product Attachment + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Preserves + + All Gender + + 115 + + 88.98 + + 220.40 +
      + All Media + + Product Attachment + + All Products + + Food + + Breakfast Foods + + All Gender + + 103 + + 87.35 + + 220.75 +
      + All Media + + Product Attachment + + All Products + + Food + + Canned Foods + + All Gender + + 564 + + 463.28 + + 1,154.91 +
      + All Media + + Product Attachment + + All Products + + Food + + Canned Products + + All Gender + + 60 + + 51.61 + + 124.24 +
      + All Media + + Product Attachment + + All Products + + Food + + Dairy + + All Gender + + 355 + + 339.81 + + 849.78 +
      + All Media + + Product Attachment + + All Products + + Food + + Deli + + All Gender + + 324 + + 243.64 + + 618.23 +
      + All Media + + Product Attachment + + All Products + + Food + + Eggs + + All Gender + + 118 + + 97.43 + + 241.21 +
      + All Media + + Product Attachment + + All Products + + Food + + Frozen Foods + + All Gender + + 812 + + 665.48 + + 1,692.11 +
      + All Media + + Product Attachment + + All Products + + Food + + Meat + + All Gender + + 54 + + 51.36 + + 127.83 +
      + All Media + + Product Attachment + + All Products + + Food + + Produce + + All Gender + + 1,069 + + 909.24 + + 2,287.61 +
      + All Media + + Product Attachment + + All Products + + Food + + Seafood + + All Gender + + 45 + + 36.98 + + 100.61 +
      + All Media + + Product Attachment + + All Products + + Food + + Snack Foods + + All Gender + + 819 + + 726.73 + + 1,847.28 +
      + All Media + + Product Attachment + + All Products + + Food + + Snacks + + All Gender + + 209 + + 186.22 + + 450.03 +
      + All Media + + Product Attachment + + All Products + + Food + + Starchy Foods + + All Gender + + 149 + + 126.59 + + 332.47 +
      + All Media + + Product Attachment + + All Products + + Non-Consumable + + All Gender + + 1,390 + + 1,179.48 + + 2,969.35 +
      + All Media + + Product Attachment + + All Products + + Non-Consumable + + Carousel + + All Gender + + 14 + + 7.99 + + 21.21 +
      + All Media + + Product Attachment + + All Products + + Non-Consumable + + Checkout + + All Gender + + 48 + + 40.45 + + 100.61 +
      + All Media + + Product Attachment + + All Products + + Non-Consumable + + Health and Hygiene + + All Gender + + 440 + + 356.54 + + 901.73 +
      + All Media + + Product Attachment + + All Products + + Non-Consumable + + Household + + All Gender + + 777 + + 690.03 + + 1,737.96 +
      + All Media + + Product Attachment + + All Products + + Non-Consumable + + Periodicals + + All Gender + + 111 + + 84.48 + + 207.84 +
      + All Media + + Radio + + All Products + + All Gender + + 2,454 + + 2,087.51 + + 5,213.61 +
      + All Media + + Radio + + All Products + + Drink + + All Gender + + 226 + + 182.85 + + 443.68 +
      + All Media + + Radio + + All Products + + Food + + All Gender + + 1,733 + + 1,485.25 + + 3,727.36 +
      + All Media + + Radio + + All Products + + Food + + Baked Goods + + All Gender + + 83 + + 76.51 + + 186.20 +
      + All Media + + Radio + + All Products + + Food + + Baking Goods + + All Gender + + 157 + + 109.10 + + 274.90 +
      + All Media + + Radio + + All Products + + Food + + Baking Goods + + Baking Goods + + All Gender + + 63 + + 45.02 + + 110.43 +
      + All Media + + Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + All Gender + + 94 + + 64.08 + + 164.47 +
      + All Media + + Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jam + + All Gender + + 15 + + 10.42 + + 26.94 +
      + All Media + + Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jelly + + All Gender + + 24 + + 14.54 + + 37.49 +
      + All Media + + Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + All Gender + + 19 + + 16.85 + + 41.82 +
      + All Media + + Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + All Gender + + 10 + + 10.58 + + 24.44 +
      + All Media + + Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + CDR + + All Gender + +   + +   + +   +
      + All Media + + Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Landslide + + All Gender + +   + +   + +   +
      + All Media + + Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Plato + + All Gender + + 4 + + 3.77 + + 9.80 +
      + All Media + + Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Super + + All Gender + + 5 + + 2.50 + + 7.58 +
      + All Media + + Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Preserves + + All Gender + + 36 + + 22.28 + + 58.22 +
      + All Media + + Radio + + All Products + + Food + + Breakfast Foods + + All Gender + + 25 + + 18.78 + + 50.22 +
      + All Media + + Radio + + All Products + + Food + + Canned Foods + + All Gender + + 158 + + 124.79 + + 307.55 +
      + All Media + + Radio + + All Products + + Food + + Canned Products + + All Gender + + 22 + + 17.29 + + 43.42 +
      + All Media + + Radio + + All Products + + Food + + Dairy + + All Gender + + 112 + + 92.12 + + 216.79 +
      + All Media + + Radio + + All Products + + Food + + Deli + + All Gender + + 129 + + 119.14 + + 307.25 +
      + All Media + + Radio + + All Products + + Food + + Eggs + + All Gender + + 25 + + 29.97 + + 71.15 +
      + All Media + + Radio + + All Products + + Food + + Frozen Foods + + All Gender + + 253 + + 202.71 + + 507.45 +
      + All Media + + Radio + + All Products + + Food + + Meat + + All Gender + + 12 + + 11.53 + + 32.85 +
      + All Media + + Radio + + All Products + + Food + + Produce + + All Gender + + 336 + + 292.05 + + 738.20 +
      + All Media + + Radio + + All Products + + Food + + Seafood + + All Gender + + 15 + + 13.28 + + 35.58 +
      + All Media + + Radio + + All Products + + Food + + Snack Foods + + All Gender + + 290 + + 270.59 + + 674.73 +
      + All Media + + Radio + + All Products + + Food + + Snacks + + All Gender + + 60 + + 55.67 + + 144.58 +
      + All Media + + Radio + + All Products + + Food + + Starchy Foods + + All Gender + + 56 + + 51.72 + + 136.49 +
      + All Media + + Radio + + All Products + + Non-Consumable + + All Gender + + 495 + + 419.41 + + 1,042.57 +
      + All Media + + Radio + + All Products + + Non-Consumable + + Carousel + + All Gender + + 15 + + 11.15 + + 26.85 +
      + All Media + + Radio + + All Products + + Non-Consumable + + Checkout + + All Gender + + 21 + + 17.00 + + 42.74 +
      + All Media + + Radio + + All Products + + Non-Consumable + + Health and Hygiene + + All Gender + + 145 + + 114.84 + + 289.80 +
      + All Media + + Radio + + All Products + + Non-Consumable + + Household + + All Gender + + 258 + + 233.31 + + 575.07 +
      + All Media + + Radio + + All Products + + Non-Consumable + + Periodicals + + All Gender + + 56 + + 43.12 + + 108.11 +
      + All Media + + Street Handout + + All Products + + All Gender + + 5,753 + + 4,856.54 + + 12,192.90 +
      + All Media + + Street Handout + + All Products + + Drink + + All Gender + + 512 + + 372.68 + + 943.42 +
      + All Media + + Street Handout + + All Products + + Food + + All Gender + + 4,239 + + 3,650.32 + + 9,151.65 +
      + All Media + + Street Handout + + All Products + + Food + + Baked Goods + + All Gender + + 160 + + 120.12 + + 301.62 +
      + All Media + + Street Handout + + All Products + + Food + + Baking Goods + + All Gender + + 498 + + 373.67 + + 923.22 +
      + All Media + + Street Handout + + All Products + + Food + + Baking Goods + + Baking Goods + + All Gender + + 200 + + 144.16 + + 357.82 +
      + All Media + + Street Handout + + All Products + + Food + + Baking Goods + + Jams and Jellies + + All Gender + + 298 + + 229.51 + + 565.40 +
      + All Media + + Street Handout + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jam + + All Gender + + 53 + + 44.30 + + 112.95 +
      + All Media + + Street Handout + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jelly + + All Gender + + 92 + + 63.14 + + 155.59 +
      + All Media + + Street Handout + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + All Gender + + 51 + + 51.06 + + 118.90 +
      + All Media + + Street Handout + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + All Gender + + 11 + + 10.85 + + 25.72 +
      + All Media + + Street Handout + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + CDR + + All Gender + + 8 + + 9.06 + + 19.73 +
      + All Media + + Street Handout + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Landslide + + All Gender + + 11 + + 6.90 + + 15.54 +
      + All Media + + Street Handout + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Plato + + All Gender + + 9 + + 8.47 + + 20.89 +
      + All Media + + Street Handout + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Super + + All Gender + + 12 + + 15.78 + + 37.02 +
      + All Media + + Street Handout + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Preserves + + All Gender + + 102 + + 71.02 + + 177.96 +
      + All Media + + Street Handout + + All Products + + Food + + Breakfast Foods + + All Gender + + 81 + + 74.32 + + 192.90 +
      + All Media + + Street Handout + + All Products + + Food + + Canned Foods + + All Gender + + 459 + + 413.21 + + 1,021.86 +
      + All Media + + Street Handout + + All Products + + Food + + Canned Products + + All Gender + + 30 + + 19.43 + + 45.68 +
      + All Media + + Street Handout + + All Products + + Food + + Dairy + + All Gender + + 301 + + 285.98 + + 718.61 +
      + All Media + + Street Handout + + All Products + + Food + + Deli + + All Gender + + 305 + + 253.54 + + 638.30 +
      + All Media + + Street Handout + + All Products + + Food + + Eggs + + All Gender + + 66 + + 59.15 + + 156.82 +
      + All Media + + Street Handout + + All Products + + Food + + Frozen Foods + + All Gender + + 612 + + 520.12 + + 1,313.71 +
      + All Media + + Street Handout + + All Products + + Food + + Meat + + All Gender + + 37 + + 29.82 + + 78.24 +
      + All Media + + Street Handout + + All Products + + Food + + Produce + + All Gender + + 745 + + 662.39 + + 1,639.94 +
      + All Media + + Street Handout + + All Products + + Food + + Seafood + + All Gender + + 37 + + 30.12 + + 72.77 +
      + All Media + + Street Handout + + All Products + + Food + + Snack Foods + + All Gender + + 675 + + 600.23 + + 1,515.68 +
      + All Media + + Street Handout + + All Products + + Food + + Snacks + + All Gender + + 144 + + 128.79 + + 321.16 +
      + All Media + + Street Handout + + All Products + + Food + + Starchy Foods + + All Gender + + 89 + + 79.43 + + 211.14 +
      + All Media + + Street Handout + + All Products + + Non-Consumable + + All Gender + + 1,002 + + 833.53 + + 2,097.83 +
      + All Media + + Street Handout + + All Products + + Non-Consumable + + Carousel + + All Gender + + 17 + + 13.53 + + 30.98 +
      + All Media + + Street Handout + + All Products + + Non-Consumable + + Checkout + + All Gender + + 45 + + 34.77 + + 85.38 +
      + All Media + + Street Handout + + All Products + + Non-Consumable + + Health and Hygiene + + All Gender + + 402 + + 318.03 + + 802.92 +
      + All Media + + Street Handout + + All Products + + Non-Consumable + + Household + + All Gender + + 501 + + 436.41 + + 1,105.38 +
      + All Media + + Street Handout + + All Products + + Non-Consumable + + Periodicals + + All Gender + + 37 + + 30.80 + + 73.17 +
      + All Media + + Sunday Paper + + All Products + + All Gender + + 4,339 + + 3,673.86 + + 9,092.89 +
      + All Media + + Sunday Paper + + All Products + + Drink + + All Gender + + 430 + + 345.53 + + 856.73 +
      + All Media + + Sunday Paper + + All Products + + Food + + All Gender + + 3,106 + + 2,646.47 + + 6,559.46 +
      + All Media + + Sunday Paper + + All Products + + Food + + Baked Goods + + All Gender + + 140 + + 110.79 + + 282.55 +
      + All Media + + Sunday Paper + + All Products + + Food + + Baking Goods + + All Gender + + 338 + + 239.76 + + 603.86 +
      + All Media + + Sunday Paper + + All Products + + Food + + Baking Goods + + Baking Goods + + All Gender + + 170 + + 118.05 + + 298.79 +
      + All Media + + Sunday Paper + + All Products + + Food + + Baking Goods + + Jams and Jellies + + All Gender + + 168 + + 121.71 + + 305.07 +
      + All Media + + Sunday Paper + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jam + + All Gender + + 24 + + 22.35 + + 54.83 +
      + All Media + + Sunday Paper + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jelly + + All Gender + + 27 + + 18.20 + + 47.12 +
      + All Media + + Sunday Paper + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + All Gender + + 51 + + 37.67 + + 96.67 +
      + All Media + + Sunday Paper + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + All Gender + + 10 + + 6.08 + + 16.22 +
      + All Media + + Sunday Paper + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + CDR + + All Gender + + 10 + + 10.47 + + 26.50 +
      + All Media + + Sunday Paper + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Landslide + + All Gender + + 15 + + 6.20 + + 16.31 +
      + All Media + + Sunday Paper + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Plato + + All Gender + + 16 + + 14.93 + + 37.64 +
      + All Media + + Sunday Paper + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Super + + All Gender + +   + +   + +   +
      + All Media + + Sunday Paper + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Preserves + + All Gender + + 66 + + 43.49 + + 106.45 +
      + All Media + + Sunday Paper + + All Products + + Food + + Breakfast Foods + + All Gender + + 55 + + 49.80 + + 120.23 +
      + All Media + + Sunday Paper + + All Products + + Food + + Canned Foods + + All Gender + + 283 + + 249.46 + + 605.11 +
      + All Media + + Sunday Paper + + All Products + + Food + + Canned Products + + All Gender + + 34 + + 29.65 + + 72.18 +
      + All Media + + Sunday Paper + + All Products + + Food + + Dairy + + All Gender + + 200 + + 201.94 + + 497.91 +
      + All Media + + Sunday Paper + + All Products + + Food + + Deli + + All Gender + + 228 + + 188.37 + + 467.53 +
      + All Media + + Sunday Paper + + All Products + + Food + + Eggs + + All Gender + + 54 + + 47.68 + + 118.44 +
      + All Media + + Sunday Paper + + All Products + + Food + + Frozen Foods + + All Gender + + 425 + + 330.81 + + 839.15 +
      + All Media + + Sunday Paper + + All Products + + Food + + Meat + + All Gender + + 18 + + 19.85 + + 52.20 +
      + All Media + + Sunday Paper + + All Products + + Food + + Produce + + All Gender + + 603 + + 520.95 + + 1,274.70 +
      + All Media + + Sunday Paper + + All Products + + Food + + Seafood + + All Gender + + 27 + + 26.82 + + 69.49 +
      + All Media + + Sunday Paper + + All Products + + Food + + Snack Foods + + All Gender + + 469 + + 413.18 + + 1,027.98 +
      + All Media + + Sunday Paper + + All Products + + Food + + Snacks + + All Gender + + 123 + + 108.50 + + 261.38 +
      + All Media + + Sunday Paper + + All Products + + Food + + Starchy Foods + + All Gender + + 109 + + 108.91 + + 266.75 +
      + All Media + + Sunday Paper + + All Products + + Non-Consumable + + All Gender + + 803 + + 681.86 + + 1,676.70 +
      + All Media + + Sunday Paper + + All Products + + Non-Consumable + + Carousel + + All Gender + + 7 + + 6.70 + + 14.68 +
      + All Media + + Sunday Paper + + All Products + + Non-Consumable + + Checkout + + All Gender + + 17 + + 13.09 + + 30.89 +
      + All Media + + Sunday Paper + + All Products + + Non-Consumable + + Health and Hygiene + + All Gender + + 278 + + 227.06 + + 565.99 +
      + All Media + + Sunday Paper + + All Products + + Non-Consumable + + Household + + All Gender + + 420 + + 371.58 + + 911.69 +
      + All Media + + Sunday Paper + + All Products + + Non-Consumable + + Periodicals + + All Gender + + 81 + + 63.43 + + 153.45 +
      + All Media + + Sunday Paper, Radio + + All Products + + All Gender + + 5,945 + + 5,027.31 + + 12,551.96 +
      + All Media + + Sunday Paper, Radio + + All Products + + Drink + + All Gender + + 591 + + 454.03 + + 1,129.94 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + All Gender + + 4,239 + + 3,612.38 + + 9,033.23 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Baked Goods + + All Gender + + 152 + + 109.11 + + 274.39 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Baking Goods + + All Gender + + 482 + + 367.13 + + 913.84 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Baking Goods + + Baking Goods + + All Gender + + 206 + + 152.72 + + 381.59 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + All Gender + + 276 + + 214.41 + + 532.25 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jam + + All Gender + + 52 + + 52.39 + + 126.62 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jelly + + All Gender + + 74 + + 53.93 + + 135.03 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + All Gender + + 64 + + 50.10 + + 126.71 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + All Gender + + 14 + + 11.58 + + 27.40 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + CDR + + All Gender + + 17 + + 14.68 + + 41.25 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Landslide + + All Gender + + 14 + + 6.62 + + 17.04 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Plato + + All Gender + + 7 + + 6.91 + + 17.15 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Super + + All Gender + + 12 + + 10.31 + + 23.87 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Preserves + + All Gender + + 86 + + 57.99 + + 143.89 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Breakfast Foods + + All Gender + + 80 + + 62.80 + + 154.04 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Canned Foods + + All Gender + + 456 + + 361.79 + + 914.81 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Canned Products + + All Gender + + 45 + + 39.72 + + 95.88 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Dairy + + All Gender + + 283 + + 296.91 + + 722.75 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Deli + + All Gender + + 252 + + 190.32 + + 479.59 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Eggs + + All Gender + + 114 + + 104.65 + + 256.15 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Frozen Foods + + All Gender + + 599 + + 490.33 + + 1,222.54 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Meat + + All Gender + + 40 + + 31.66 + + 84.76 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Produce + + All Gender + + 858 + + 752.62 + + 1,886.01 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Seafood + + All Gender + + 27 + + 20.66 + + 50.39 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Snack Foods + + All Gender + + 596 + + 555.70 + + 1,402.21 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Snacks + + All Gender + + 147 + + 120.43 + + 304.18 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Starchy Foods + + All Gender + + 108 + + 108.55 + + 271.69 +
      + All Media + + Sunday Paper, Radio + + All Products + + Non-Consumable + + All Gender + + 1,115 + + 960.90 + + 2,388.79 +
      + All Media + + Sunday Paper, Radio + + All Products + + Non-Consumable + + Carousel + + All Gender + + 18 + + 10.99 + + 26.94 +
      + All Media + + Sunday Paper, Radio + + All Products + + Non-Consumable + + Checkout + + All Gender + + 26 + + 24.68 + + 62.14 +
      + All Media + + Sunday Paper, Radio + + All Products + + Non-Consumable + + Health and Hygiene + + All Gender + + 378 + + 309.37 + + 771.48 +
      + All Media + + Sunday Paper, Radio + + All Products + + Non-Consumable + + Household + + All Gender + + 585 + + 516.99 + + 1,276.16 +
      + All Media + + Sunday Paper, Radio + + All Products + + Non-Consumable + + Periodicals + + All Gender + + 108 + + 98.86 + + 252.07 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + All Gender + + 2,726 + + 2,341.58 + + 5,819.33 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Drink + + All Gender + + 225 + + 163.09 + + 403.51 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + All Gender + + 2,021 + + 1,762.18 + + 4,377.85 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Baked Goods + + All Gender + + 67 + + 66.17 + + 163.29 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Baking Goods + + All Gender + + 228 + + 182.98 + + 455.90 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Baking Goods + + Baking Goods + + All Gender + + 90 + + 73.09 + + 176.63 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + All Gender + + 138 + + 109.90 + + 279.27 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jam + + All Gender + + 37 + + 31.30 + + 78.56 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jelly + + All Gender + + 27 + + 16.18 + + 39.92 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + All Gender + + 30 + + 24.01 + + 64.19 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + All Gender + + 11 + + 9.78 + + 23.86 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + CDR + + All Gender + +   + +   + +   +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Landslide + + All Gender + + 4 + + 2.39 + + 5.68 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Plato + + All Gender + + 5 + + 3.85 + + 11.60 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Super + + All Gender + + 10 + + 7.99 + + 23.05 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Preserves + + All Gender + + 44 + + 38.41 + + 96.60 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Breakfast Foods + + All Gender + + 38 + + 32.76 + + 89.85 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Canned Foods + + All Gender + + 180 + + 138.77 + + 340.04 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Canned Products + + All Gender + + 14 + + 12.00 + + 28.28 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Dairy + + All Gender + + 121 + + 125.32 + + 305.43 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Deli + + All Gender + + 131 + + 98.93 + + 245.42 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Eggs + + All Gender + + 39 + + 39.57 + + 91.99 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Frozen Foods + + All Gender + + 279 + + 207.59 + + 514.95 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Meat + + All Gender + + 12 + + 11.77 + + 30.23 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Produce + + All Gender + + 411 + + 382.14 + + 943.93 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Seafood + + All Gender + + 31 + + 28.07 + + 69.82 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Snack Foods + + All Gender + + 346 + + 318.26 + + 798.50 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Snacks + + All Gender + + 75 + + 65.49 + + 174.02 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Starchy Foods + + All Gender + + 49 + + 52.37 + + 126.20 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Non-Consumable + + All Gender + + 480 + + 416.30 + + 1,037.97 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Non-Consumable + + Carousel + + All Gender + + 21 + + 11.63 + + 27.92 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Non-Consumable + + Checkout + + All Gender + + 10 + + 8.12 + + 19.80 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Non-Consumable + + Health and Hygiene + + All Gender + + 138 + + 110.35 + + 276.31 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Non-Consumable + + Household + + All Gender + + 262 + + 244.90 + + 608.52 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Non-Consumable + + Periodicals + + All Gender + + 49 + + 41.30 + + 105.42 +
      + All Media + + TV + + All Products + + All Gender + + 3,607 + + 3,116.40 + + 7,786.21 +
      + All Media + + TV + + All Products + + Drink + + All Gender + + 332 + + 283.18 + + 721.07 +
      + All Media + + TV + + All Products + + Food + + All Gender + + 2,563 + + 2,238.13 + + 5,573.27 +
      + All Media + + TV + + All Products + + Food + + Baked Goods + + All Gender + + 114 + + 103.40 + + 262.97 +
      + All Media + + TV + + All Products + + Food + + Baking Goods + + All Gender + + 237 + + 185.55 + + 464.23 +
      + All Media + + TV + + All Products + + Food + + Baking Goods + + Baking Goods + + All Gender + + 95 + + 74.29 + + 190.59 +
      + All Media + + TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + All Gender + + 142 + + 111.25 + + 273.64 +
      + All Media + + TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jam + + All Gender + + 38 + + 32.28 + + 77.58 +
      + All Media + + TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jelly + + All Gender + + 35 + + 24.64 + + 63.38 +
      + All Media + + TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + All Gender + + 31 + + 21.83 + + 56.80 +
      + All Media + + TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + All Gender + +   + +   + +   +
      + All Media + + TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + CDR + + All Gender + + 11 + + 9.78 + + 27.19 +
      + All Media + + TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Landslide + + All Gender + + 7 + + 2.61 + + 7.12 +
      + All Media + + TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Plato + + All Gender + + 6 + + 4.95 + + 12.13 +
      + All Media + + TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Super + + All Gender + + 7 + + 4.48 + + 10.36 +
      + All Media + + TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Preserves + + All Gender + + 38 + + 32.51 + + 75.88 +
      + All Media + + TV + + All Products + + Food + + Breakfast Foods + + All Gender + + 36 + + 30.11 + + 79.89 +
      + All Media + + TV + + All Products + + Food + + Canned Foods + + All Gender + + 240 + + 200.00 + + 519.91 +
      + All Media + + TV + + All Products + + Food + + Canned Products + + All Gender + + 26 + + 15.00 + + 38.65 +
      + All Media + + TV + + All Products + + Food + + Dairy + + All Gender + + 179 + + 183.73 + + 458.87 +
      + All Media + + TV + + All Products + + Food + + Deli + + All Gender + + 155 + + 139.76 + + 342.51 +
      + All Media + + TV + + All Products + + Food + + Eggs + + All Gender + + 42 + + 32.74 + + 80.93 +
      + All Media + + TV + + All Products + + Food + + Frozen Foods + + All Gender + + 352 + + 300.42 + + 738.40 +
      + All Media + + TV + + All Products + + Food + + Meat + + All Gender + + 22 + + 19.76 + + 49.27 +
      + All Media + + TV + + All Products + + Food + + Produce + + All Gender + + 543 + + 456.53 + + 1,145.45 +
      + All Media + + TV + + All Products + + Food + + Seafood + + All Gender + + 34 + + 30.71 + + 75.47 +
      + All Media + + TV + + All Products + + Food + + Snack Foods + + All Gender + + 401 + + 377.01 + + 927.50 +
      + All Media + + TV + + All Products + + Food + + Snacks + + All Gender + + 99 + + 92.80 + + 220.54 +
      + All Media + + TV + + All Products + + Food + + Starchy Foods + + All Gender + + 83 + + 70.61 + + 168.68 +
      + All Media + + TV + + All Products + + Non-Consumable + + All Gender + + 712 + + 595.08 + + 1,491.87 +
      + All Media + + TV + + All Products + + Non-Consumable + + Carousel + + All Gender + + 4 + + 3.13 + + 9.20 +
      + All Media + + TV + + All Products + + Non-Consumable + + Checkout + + All Gender + + 34 + + 34.12 + + 86.21 +
      + All Media + + TV + + All Products + + Non-Consumable + + Health and Hygiene + + All Gender + + 249 + + 196.08 + + 486.46 +
      + All Media + + TV + + All Products + + Non-Consumable + + Household + + All Gender + + 361 + + 316.09 + + 795.40 +
      + All Media + + TV + + All Products + + Non-Consumable + + Periodicals + + All Gender + + 64 + + 45.67 + + 114.60 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/insane-rows-true-true-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/insane-rows-true-true-false-result.html index 994207ee..2bf1a619 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/insane-rows-true-true-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/insane-rows-true-true-false-result.html @@ -1,7960 +1,7960 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Measures - - Measures - - Measures -
      - Promotion Media - - Product - - Gender - - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - All Products - - All Gender - - 266,773 - - 225,627.23 - - 565,238.13 -
      - All Media - - Drink - - All Gender - - 24,597 - - 19,477.23 - - 48,836.21 -
      - All Media - - Food - - All Gender - - 191,940 - - 163,270.72 - - 409,035.59 -
      - All Media - - Baked Goods - - All Gender - - 7,870 - - 6,564.09 - - 16,455.43 -
      - All Media - - Baking Goods - - All Gender - - 20,245 - - 15,370.61 - - 38,670.41 -
      - All Media - - Baking Goods - - All Gender - - 8,357 - - 6,123.32 - - 15,446.69 -
      - All Media - - Baking Goods - - F - - 4,005 - - 2,907.70 - - 7,313.61 -
      - All Media - - Baking Goods - - M - - 4,352 - - 3,215.62 - - 8,133.08 -
      - All Media - - Jams and Jellies - - All Gender - - 11,888 - - 9,247.29 - - 23,223.72 -
      - All Media - - Jam - - All Gender - - 2,556 - - 2,132.27 - - 5,401.81 -
      - All Media - - Jelly - - All Gender - - 2,565 - - 1,830.04 - - 4,609.61 -
      - All Media - - Jelly - - F - - 1,309 - - 956.94 - - 2,414.94 -
      - All Media - - Jelly - - M - - 1,256 - - 873.10 - - 2,194.67 -
      - All Media - - Peanut Butter - - All Gender - - 2,667 - - 2,097.37 - - 5,231.08 -
      - All Media - - BBB Best - - All Gender - - 556 - - 424.38 - - 1,055.72 -
      - All Media - - BBB Best - - F - - 271 - - 201.08 - - 500.39 -
      - All Media - - BBB Best - - M - - 285 - - 223.30 - - 555.33 -
      - All Media - - BBB Best Chunky Peanut Butter - - All Gender - - 188 - - 147.32 - - 370.36 -
      - All Media - - BBB Best Chunky Peanut Butter - - F - - 107 - - 85.81 - - 210.79 -
      - All Media - - BBB Best Chunky Peanut Butter - - M - - 81 - - 61.50 - - 159.57 -
      - All Media - - BBB Best Creamy Peanut Butter - - All Gender - - 201 - - 87.86 - - 221.10 -
      - All Media - - BBB Best Creamy Peanut Butter - - F - - 99 - - 43.35 - - 108.90 -
      - All Media - - BBB Best Creamy Peanut Butter - - M - - 102 - - 44.51 - - 112.20 -
      - All Media - - BBB Best Extra Chunky Peanut Butter - - All Gender - - 167 - - 189.21 - - 464.26 -
      - All Media - - BBB Best Extra Chunky Peanut Butter - - F - - 65 - - 71.92 - - 180.70 -
      - All Media - - BBB Best Extra Chunky Peanut Butter - - M - - 102 - - 117.29 - - 283.56 -
      - All Media - - CDR - - All Gender - - 545 - - 538.88 - - 1,326.30 -
      - All Media - - Landslide - - All Gender - - 531 - - 256.16 - - 635.29 -
      - All Media - - Plato - - All Gender - - 520 - - 447.73 - - 1,132.16 -
      - All Media - - Super - - All Gender - - 515 - - 430.21 - - 1,081.61 -
      - All Media - - Preserves - - All Gender - - 4,100 - - 3,187.61 - - 7,981.22 -
      - All Media - - Preserves - - F - - 1,946 - - 1,472.42 - - 3,717.80 -
      - All Media - - Preserves - - M - - 2,154 - - 1,715.19 - - 4,263.42 -
      - All Media - - Breakfast Foods - - All Gender - - 3,317 - - 2,756.80 - - 6,941.46 -
      - All Media - - Canned Foods - - All Gender - - 19,026 - - 15,894.53 - - 39,774.34 -
      - All Media - - Canned Anchovies - - All Gender - - 900 - - 913.88 - - 2,296.38 -
      - All Media - - Canned Clams - - All Gender - - 882 - - 759.80 - - 1,912.68 -
      - All Media - - Clams - - All Gender - - 882 - - 759.80 - - 1,912.68 -
      - All Media - - Better - - All Gender - - 189 - - 151.14 - - 398.79 -
      - All Media - - Blue Label - - All Gender - - 165 - - 112.82 - - 278.85 -
      - All Media - - Bravo - - All Gender - - 184 - - 280.70 - - 708.40 -
      - All Media - - Just Right - - All Gender - - 177 - - 161.96 - - 394.71 -
      - All Media - - Pleasant - - All Gender - - 167 - - 53.17 - - 131.93 -
      - All Media - - Canned Oysters - - All Gender - - 708 - - 571.50 - - 1,442.77 -
      - All Media - - Canned Sardines - - All Gender - - 819 - - 537.59 - - 1,357.80 -
      - All Media - - Canned Shrimp - - All Gender - - 804 - - 858.39 - - 2,146.49 -
      - All Media - - Canned Soup - - All Gender - - 8,006 - - 6,408.29 - - 15,966.10 -
      - All Media - - Canned Tuna - - All Gender - - 1,710 - - 1,288.52 - - 3,210.76 -
      - All Media - - Vegetables - - All Gender - - 5,197 - - 4,556.57 - - 11,441.36 -
      - All Media - - Canned Products - - All Gender - - 1,812 - - 1,317.13 - - 3,314.52 -
      - All Media - - Dairy - - All Gender - - 12,885 - - 12,228.85 - - 30,508.85 -
      - All Media - - Deli - - All Gender - - 12,037 - - 10,108.87 - - 25,318.93 -
      - All Media - - Meat - - All Gender - - 9,433 - - 8,215.81 - - 20,616.29 -
      - All Media - - Bologna - - All Gender - - 2,588 - - 2,340.24 - - 5,859.95 -
      - All Media - - Deli Meats - - All Gender - - 3,339 - - 2,851.18 - - 7,191.24 -
      - All Media - - Deli Meats - - F - - 1,653 - - 1,414.49 - - 3,579.34 -
      - All Media - - Deli Meats - - M - - 1,686 - - 1,436.69 - - 3,611.90 -
      - All Media - - Fresh Chicken - - All Gender - - 878 - - 842.85 - - 2,091.52 -
      - All Media - - Hot Dogs - - All Gender - - 2,628 - - 2,181.55 - - 5,473.58 -
      - All Media - - Side Dishes - - All Gender - - 2,604 - - 1,893.06 - - 4,702.64 -
      - All Media - - Eggs - - All Gender - - 4,132 - - 3,684.90 - - 9,200.76 -
      - All Media - - Frozen Foods - - All Gender - - 26,655 - - 22,030.66 - - 55,207.50 -
      - All Media - - Meat - - All Gender - - 1,714 - - 1,465.42 - - 3,669.89 -
      - All Media - - Produce - - All Gender - - 37,792 - - 32,831.33 - - 82,248.42 -
      - All Media - - Seafood - - All Gender - - 1,764 - - 1,520.70 - - 3,809.14 -
      - All Media - - Snack Foods - - All Gender - - 30,545 - - 26,963.34 - - 67,609.82 -
      - All Media - - Snacks - - All Gender - - 6,884 - - 5,827.58 - - 14,550.05 -
      - All Media - - Starchy Foods - - All Gender - - 5,262 - - 4,705.91 - - 11,756.07 -
      - All Media - - Non-Consumable - - All Gender - - 50,236 - - 42,879.28 - - 107,366.33 -
      - All Media - - Carousel - - All Gender - - 841 - - 595.97 - - 1,500.11 -
      - All Media - - Checkout - - All Gender - - 1,779 - - 1,525.04 - - 3,767.71 -
      - All Media - - Health and Hygiene - - All Gender - - 16,284 - - 12,972.99 - - 32,571.86 -
      - All Media - - Household - - All Gender - - 27,038 - - 24,170.73 - - 60,469.89 -
      - All Media - - Periodicals - - All Gender - - 4,294 - - 3,614.55 - - 9,056.76 -
      - Bulk Mail - - All Products - - All Gender - - 4,320 - - 3,740.95 - - 9,349.07 -
      - Cash Register Handout - - All Products - - All Gender - - 6,697 - - 5,715.67 - - 14,321.33 -
      - Daily Paper - - All Products - - All Gender - - 7,738 - - 6,559.23 - - 16,479.81 -
      - Daily Paper, Radio - - All Products - - All Gender - - 6,891 - - 5,668.77 - - 14,169.42 -
      - Daily Paper, Radio, TV - - All Products - - All Gender - - 9,513 - - 8,055.22 - - 20,173.97 -
      - In-Store Coupon - - All Products - - All Gender - - 3,798 - - 3,263.11 - - 8,162.46 -
      - In-Store Coupon - - Drink - - All Gender - - 345 - - 282.44 - - 708.38 -
      - In-Store Coupon - - Food - - All Gender - - 2,737 - - 2,345.57 - - 5,889.34 -
      - In-Store Coupon - - Baked Goods - - All Gender - - 131 - - 114.11 - - 279.11 -
      - In-Store Coupon - - Baking Goods - - All Gender - - 308 - - 252.88 - - 632.01 -
      - In-Store Coupon - - Baking Goods - - All Gender - - 146 - - 103.30 - - 261.44 -
      - In-Store Coupon - - Jams and Jellies - - All Gender - - 162 - - 149.58 - - 370.57 -
      - In-Store Coupon - - Jam - - All Gender - - 55 - - 58.16 - - 141.19 -
      - In-Store Coupon - - Jelly - - All Gender - - 32 - - 23.96 - - 62.12 -
      - In-Store Coupon - - Peanut Butter - - All Gender - - 22 - - 19.54 - - 48.72 -
      - In-Store Coupon - - BBB Best - - All Gender - - 7 - - 6.72 - - 16.10 -
      - In-Store Coupon - - CDR - - All Gender - - 10 - - 9.81 - - 24.32 -
      - In-Store Coupon - - Landslide - - All Gender - -   - -   - -   -
      - In-Store Coupon - - Plato - - All Gender - - 3 - - 2.32 - - 6.32 -
      - In-Store Coupon - - Super - - All Gender - - 2 - - .69 - - 1.98 -
      - In-Store Coupon - - Preserves - - All Gender - - 53 - - 47.92 - - 118.54 -
      - In-Store Coupon - - Breakfast Foods - - All Gender - - 59 - - 49.22 - - 125.19 -
      - In-Store Coupon - - Breakfast Foods - - F - - 33 - - 22.88 - - 54.84 -
      - In-Store Coupon - - Breakfast Foods - - M - - 26 - - 26.34 - - 70.35 -
      - In-Store Coupon - - Canned Foods - - All Gender - - 245 - - 200.61 - - 506.67 -
      - In-Store Coupon - - Canned Products - - All Gender - - 15 - - 9.58 - - 26.17 -
      - In-Store Coupon - - Dairy - - All Gender - - 166 - - 153.42 - - 372.01 -
      - In-Store Coupon - - Deli - - All Gender - - 180 - - 163.58 - - 392.68 -
      - In-Store Coupon - - Eggs - - All Gender - - 56 - - 42.51 - - 108.90 -
      - In-Store Coupon - - Frozen Foods - - All Gender - - 374 - - 301.63 - - 773.52 -
      - In-Store Coupon - - Meat - - All Gender - - 31 - - 23.91 - - 70.35 -
      - In-Store Coupon - - Produce - - All Gender - - 563 - - 499.63 - - 1,257.05 -
      - In-Store Coupon - - Seafood - - All Gender - - 34 - - 30.06 - - 76.09 -
      - In-Store Coupon - - Snack Foods - - All Gender - - 439 - - 390.35 - - 989.13 -
      - In-Store Coupon - - Snacks - - All Gender - - 78 - - 63.77 - - 153.02 -
      - In-Store Coupon - - Starchy Foods - - All Gender - - 58 - - 50.30 - - 127.44 -
      - In-Store Coupon - - Non-Consumable - - All Gender - - 716 - - 635.10 - - 1,564.74 -
      - In-Store Coupon - - Carousel - - All Gender - - 17 - - 8.77 - - 24.18 -
      - In-Store Coupon - - Checkout - - All Gender - - 23 - - 15.20 - - 40.19 -
      - In-Store Coupon - - Health and Hygiene - - All Gender - - 251 - - 193.53 - - 477.21 -
      - In-Store Coupon - - Household - - All Gender - - 374 - - 375.66 - - 916.97 -
      - In-Store Coupon - - Periodicals - - All Gender - - 51 - - 41.94 - - 106.19 -
      - No Media - - All Products - - All Gender - - 195,448 - - 165,214.85 - - 414,026.92 -
      - No Media - - Drink - - All Gender - - 17,896 - - 14,211.41 - - 35,681.85 -
      - No Media - - Food - - All Gender - - 140,577 - - 119,469.36 - - 299,356.11 -
      - No Media - - Baked Goods - - All Gender - - 5,753 - - 4,775.86 - - 11,972.46 -
      - No Media - - Baking Goods - - All Gender - - 14,849 - - 11,226.15 - - 28,312.78 -
      - No Media - - Baking Goods - - All Gender - - 5,979 - - 4,347.34 - - 11,002.73 -
      - No Media - - Jams and Jellies - - All Gender - - 8,870 - - 6,878.81 - - 17,310.05 -
      - No Media - - Jam - - All Gender - - 1,883 - - 1,554.13 - - 3,965.74 -
      - No Media - - Jelly - - All Gender - - 1,936 - - 1,394.32 - - 3,504.71 -
      - No Media - - Peanut Butter - - All Gender - - 1,984 - - 1,534.19 - - 3,828.01 -
      - No Media - - BBB Best - - All Gender - - 406 - - 293.97 - - 735.29 -
      - No Media - - CDR - - All Gender - - 411 - - 401.88 - - 998.12 -
      - No Media - - Landslide - - All Gender - - 401 - - 195.51 - - 478.44 -
      - No Media - - Plato - - All Gender - - 384 - - 331.26 - - 832.92 -
      - No Media - - Super - - All Gender - - 382 - - 311.57 - - 783.24 -
      - No Media - - Preserves - - All Gender - - 3,067 - - 2,396.16 - - 6,011.59 -
      - No Media - - Breakfast Foods - - All Gender - - 2,418 - - 1,996.45 - - 5,016.10 -
      - No Media - - Canned Foods - - All Gender - - 13,861 - - 11,647.47 - - 29,102.79 -
      - No Media - - Canned Products - - All Gender - - 1,344 - - 960.82 - - 2,424.98 -
      - No Media - - Dairy - - All Gender - - 9,510 - - 8,981.13 - - 22,454.02 -
      - No Media - - Deli - - All Gender - - 8,695 - - 7,353.56 - - 18,410.26 -
      - No Media - - Eggs - - All Gender - - 2,976 - - 2,640.47 - - 6,606.25 -
      - No Media - - Frozen Foods - - All Gender - - 19,450 - - 16,127.24 - - 40,411.08 -
      - No Media - - Meat - - All Gender - - 1,236 - - 1,068.07 - - 2,646.00 -
      - No Media - - Produce - - All Gender - - 27,637 - - 24,036.36 - - 60,203.58 -
      - No Media - - Seafood - - All Gender - - 1,292 - - 1,114.69 - - 2,774.43 -
      - No Media - - Snack Foods - - All Gender - - 22,525 - - 19,800.82 - - 49,680.71 -
      - No Media - - Snacks - - All Gender - - 5,100 - - 4,264.55 - - 10,690.26 -
      - No Media - - Starchy Foods - - All Gender - - 3,931 - - 3,475.74 - - 8,650.41 -
      - No Media - - Non-Consumable - - All Gender - - 36,975 - - 31,534.08 - - 78,988.96 -
      - No Media - - Carousel - - All Gender - - 584 - - 419.65 - - 1,050.75 -
      - No Media - - Checkout - - All Gender - - 1,305 - - 1,113.97 - - 2,768.66 -
      - No Media - - Health and Hygiene - - All Gender - - 11,845 - - 9,413.25 - - 23,621.12 -
      - No Media - - Household - - All Gender - - 20,091 - - 17,929.20 - - 44,881.13 -
      - No Media - - Periodicals - - All Gender - - 3,150 - - 2,658.00 - - 6,667.30 -
      - Product Attachment - - All Products - - All Gender - - 7,544 - - 6,306.24 - - 15,898.25 -
      - Product Attachment - - Drink - - All Gender - - 713 - - 555.05 - - 1,403.65 -
      - Product Attachment - - Food - - All Gender - - 5,441 - - 4,571.71 - - 11,525.25 -
      - Product Attachment - - Baked Goods - - All Gender - - 213 - - 175.69 - - 445.60 -
      - Product Attachment - - Baking Goods - - All Gender - - 547 - - 410.31 - - 1,032.59 -
      - Product Attachment - - Baking Goods - - All Gender - - 258 - - 191.48 - - 470.58 -
      - Product Attachment - - Jams and Jellies - - All Gender - - 289 - - 218.83 - - 562.01 -
      - Product Attachment - - Jam - - All Gender - - 66 - - 48.03 - - 128.68 -
      - Product Attachment - - Jelly - - All Gender - - 45 - - 34.12 - - 90.62 -
      - Product Attachment - - Peanut Butter - - All Gender - - 63 - - 47.71 - - 122.31 -
      - Product Attachment - - BBB Best - - All Gender - - 15 - - 14.53 - - 38.46 -
      - Product Attachment - - CDR - - All Gender - - 13 - - 11.94 - - 30.57 -
      - Product Attachment - - Landslide - - All Gender - - 12 - - 5.32 - - 14.28 -
      - Product Attachment - - Plato - - All Gender - - 9 - - 7.16 - - 17.43 -
      - Product Attachment - - Super - - All Gender - - 14 - - 8.75 - - 21.57 -
      - Product Attachment - - Preserves - - All Gender - - 115 - - 88.98 - - 220.40 -
      - Product Attachment - - Breakfast Foods - - All Gender - - 103 - - 87.35 - - 220.75 -
      - Product Attachment - - Canned Foods - - All Gender - - 564 - - 463.28 - - 1,154.91 -
      - Product Attachment - - Canned Products - - All Gender - - 60 - - 51.61 - - 124.24 -
      - Product Attachment - - Dairy - - All Gender - - 355 - - 339.81 - - 849.78 -
      - Product Attachment - - Deli - - All Gender - - 324 - - 243.64 - - 618.23 -
      - Product Attachment - - Eggs - - All Gender - - 118 - - 97.43 - - 241.21 -
      - Product Attachment - - Frozen Foods - - All Gender - - 812 - - 665.48 - - 1,692.11 -
      - Product Attachment - - Meat - - All Gender - - 54 - - 51.36 - - 127.83 -
      - Product Attachment - - Produce - - All Gender - - 1,069 - - 909.24 - - 2,287.61 -
      - Product Attachment - - Seafood - - All Gender - - 45 - - 36.98 - - 100.61 -
      - Product Attachment - - Snack Foods - - All Gender - - 819 - - 726.73 - - 1,847.28 -
      - Product Attachment - - Snacks - - All Gender - - 209 - - 186.22 - - 450.03 -
      - Product Attachment - - Starchy Foods - - All Gender - - 149 - - 126.59 - - 332.47 -
      - Product Attachment - - Non-Consumable - - All Gender - - 1,390 - - 1,179.48 - - 2,969.35 -
      - Product Attachment - - Carousel - - All Gender - - 14 - - 7.99 - - 21.21 -
      - Product Attachment - - Checkout - - All Gender - - 48 - - 40.45 - - 100.61 -
      - Product Attachment - - Health and Hygiene - - All Gender - - 440 - - 356.54 - - 901.73 -
      - Product Attachment - - Household - - All Gender - - 777 - - 690.03 - - 1,737.96 -
      - Product Attachment - - Periodicals - - All Gender - - 111 - - 84.48 - - 207.84 -
      - Radio - - All Products - - All Gender - - 2,454 - - 2,087.51 - - 5,213.61 -
      - Radio - - Drink - - All Gender - - 226 - - 182.85 - - 443.68 -
      - Radio - - Food - - All Gender - - 1,733 - - 1,485.25 - - 3,727.36 -
      - Radio - - Baked Goods - - All Gender - - 83 - - 76.51 - - 186.20 -
      - Radio - - Baking Goods - - All Gender - - 157 - - 109.10 - - 274.90 -
      - Radio - - Baking Goods - - All Gender - - 63 - - 45.02 - - 110.43 -
      - Radio - - Jams and Jellies - - All Gender - - 94 - - 64.08 - - 164.47 -
      - Radio - - Jam - - All Gender - - 15 - - 10.42 - - 26.94 -
      - Radio - - Jelly - - All Gender - - 24 - - 14.54 - - 37.49 -
      - Radio - - Peanut Butter - - All Gender - - 19 - - 16.85 - - 41.82 -
      - Radio - - BBB Best - - All Gender - - 10 - - 10.58 - - 24.44 -
      - Radio - - CDR - - All Gender - -   - -   - -   -
      - Radio - - Landslide - - All Gender - -   - -   - -   -
      - Radio - - Plato - - All Gender - - 4 - - 3.77 - - 9.80 -
      - Radio - - Super - - All Gender - - 5 - - 2.50 - - 7.58 -
      - Radio - - Preserves - - All Gender - - 36 - - 22.28 - - 58.22 -
      - Radio - - Breakfast Foods - - All Gender - - 25 - - 18.78 - - 50.22 -
      - Radio - - Canned Foods - - All Gender - - 158 - - 124.79 - - 307.55 -
      - Radio - - Canned Products - - All Gender - - 22 - - 17.29 - - 43.42 -
      - Radio - - Dairy - - All Gender - - 112 - - 92.12 - - 216.79 -
      - Radio - - Deli - - All Gender - - 129 - - 119.14 - - 307.25 -
      - Radio - - Eggs - - All Gender - - 25 - - 29.97 - - 71.15 -
      - Radio - - Frozen Foods - - All Gender - - 253 - - 202.71 - - 507.45 -
      - Radio - - Meat - - All Gender - - 12 - - 11.53 - - 32.85 -
      - Radio - - Produce - - All Gender - - 336 - - 292.05 - - 738.20 -
      - Radio - - Seafood - - All Gender - - 15 - - 13.28 - - 35.58 -
      - Radio - - Snack Foods - - All Gender - - 290 - - 270.59 - - 674.73 -
      - Radio - - Snacks - - All Gender - - 60 - - 55.67 - - 144.58 -
      - Radio - - Starchy Foods - - All Gender - - 56 - - 51.72 - - 136.49 -
      - Radio - - Non-Consumable - - All Gender - - 495 - - 419.41 - - 1,042.57 -
      - Radio - - Carousel - - All Gender - - 15 - - 11.15 - - 26.85 -
      - Radio - - Checkout - - All Gender - - 21 - - 17.00 - - 42.74 -
      - Radio - - Health and Hygiene - - All Gender - - 145 - - 114.84 - - 289.80 -
      - Radio - - Household - - All Gender - - 258 - - 233.31 - - 575.07 -
      - Radio - - Periodicals - - All Gender - - 56 - - 43.12 - - 108.11 -
      - Street Handout - - All Products - - All Gender - - 5,753 - - 4,856.54 - - 12,192.90 -
      - Street Handout - - Drink - - All Gender - - 512 - - 372.68 - - 943.42 -
      - Street Handout - - Food - - All Gender - - 4,239 - - 3,650.32 - - 9,151.65 -
      - Street Handout - - Baked Goods - - All Gender - - 160 - - 120.12 - - 301.62 -
      - Street Handout - - Baking Goods - - All Gender - - 498 - - 373.67 - - 923.22 -
      - Street Handout - - Baking Goods - - All Gender - - 200 - - 144.16 - - 357.82 -
      - Street Handout - - Jams and Jellies - - All Gender - - 298 - - 229.51 - - 565.40 -
      - Street Handout - - Jam - - All Gender - - 53 - - 44.30 - - 112.95 -
      - Street Handout - - Jelly - - All Gender - - 92 - - 63.14 - - 155.59 -
      - Street Handout - - Peanut Butter - - All Gender - - 51 - - 51.06 - - 118.90 -
      - Street Handout - - BBB Best - - All Gender - - 11 - - 10.85 - - 25.72 -
      - Street Handout - - CDR - - All Gender - - 8 - - 9.06 - - 19.73 -
      - Street Handout - - Landslide - - All Gender - - 11 - - 6.90 - - 15.54 -
      - Street Handout - - Plato - - All Gender - - 9 - - 8.47 - - 20.89 -
      - Street Handout - - Super - - All Gender - - 12 - - 15.78 - - 37.02 -
      - Street Handout - - Preserves - - All Gender - - 102 - - 71.02 - - 177.96 -
      - Street Handout - - Breakfast Foods - - All Gender - - 81 - - 74.32 - - 192.90 -
      - Street Handout - - Canned Foods - - All Gender - - 459 - - 413.21 - - 1,021.86 -
      - Street Handout - - Canned Products - - All Gender - - 30 - - 19.43 - - 45.68 -
      - Street Handout - - Dairy - - All Gender - - 301 - - 285.98 - - 718.61 -
      - Street Handout - - Deli - - All Gender - - 305 - - 253.54 - - 638.30 -
      - Street Handout - - Eggs - - All Gender - - 66 - - 59.15 - - 156.82 -
      - Street Handout - - Frozen Foods - - All Gender - - 612 - - 520.12 - - 1,313.71 -
      - Street Handout - - Meat - - All Gender - - 37 - - 29.82 - - 78.24 -
      - Street Handout - - Produce - - All Gender - - 745 - - 662.39 - - 1,639.94 -
      - Street Handout - - Seafood - - All Gender - - 37 - - 30.12 - - 72.77 -
      - Street Handout - - Snack Foods - - All Gender - - 675 - - 600.23 - - 1,515.68 -
      - Street Handout - - Snacks - - All Gender - - 144 - - 128.79 - - 321.16 -
      - Street Handout - - Starchy Foods - - All Gender - - 89 - - 79.43 - - 211.14 -
      - Street Handout - - Non-Consumable - - All Gender - - 1,002 - - 833.53 - - 2,097.83 -
      - Street Handout - - Carousel - - All Gender - - 17 - - 13.53 - - 30.98 -
      - Street Handout - - Checkout - - All Gender - - 45 - - 34.77 - - 85.38 -
      - Street Handout - - Health and Hygiene - - All Gender - - 402 - - 318.03 - - 802.92 -
      - Street Handout - - Household - - All Gender - - 501 - - 436.41 - - 1,105.38 -
      - Street Handout - - Periodicals - - All Gender - - 37 - - 30.80 - - 73.17 -
      - Sunday Paper - - All Products - - All Gender - - 4,339 - - 3,673.86 - - 9,092.89 -
      - Sunday Paper - - Drink - - All Gender - - 430 - - 345.53 - - 856.73 -
      - Sunday Paper - - Food - - All Gender - - 3,106 - - 2,646.47 - - 6,559.46 -
      - Sunday Paper - - Baked Goods - - All Gender - - 140 - - 110.79 - - 282.55 -
      - Sunday Paper - - Baking Goods - - All Gender - - 338 - - 239.76 - - 603.86 -
      - Sunday Paper - - Baking Goods - - All Gender - - 170 - - 118.05 - - 298.79 -
      - Sunday Paper - - Jams and Jellies - - All Gender - - 168 - - 121.71 - - 305.07 -
      - Sunday Paper - - Jam - - All Gender - - 24 - - 22.35 - - 54.83 -
      - Sunday Paper - - Jelly - - All Gender - - 27 - - 18.20 - - 47.12 -
      - Sunday Paper - - Peanut Butter - - All Gender - - 51 - - 37.67 - - 96.67 -
      - Sunday Paper - - BBB Best - - All Gender - - 10 - - 6.08 - - 16.22 -
      - Sunday Paper - - CDR - - All Gender - - 10 - - 10.47 - - 26.50 -
      - Sunday Paper - - Landslide - - All Gender - - 15 - - 6.20 - - 16.31 -
      - Sunday Paper - - Plato - - All Gender - - 16 - - 14.93 - - 37.64 -
      - Sunday Paper - - Super - - All Gender - -   - -   - -   -
      - Sunday Paper - - Preserves - - All Gender - - 66 - - 43.49 - - 106.45 -
      - Sunday Paper - - Breakfast Foods - - All Gender - - 55 - - 49.80 - - 120.23 -
      - Sunday Paper - - Canned Foods - - All Gender - - 283 - - 249.46 - - 605.11 -
      - Sunday Paper - - Canned Products - - All Gender - - 34 - - 29.65 - - 72.18 -
      - Sunday Paper - - Dairy - - All Gender - - 200 - - 201.94 - - 497.91 -
      - Sunday Paper - - Deli - - All Gender - - 228 - - 188.37 - - 467.53 -
      - Sunday Paper - - Eggs - - All Gender - - 54 - - 47.68 - - 118.44 -
      - Sunday Paper - - Frozen Foods - - All Gender - - 425 - - 330.81 - - 839.15 -
      - Sunday Paper - - Meat - - All Gender - - 18 - - 19.85 - - 52.20 -
      - Sunday Paper - - Produce - - All Gender - - 603 - - 520.95 - - 1,274.70 -
      - Sunday Paper - - Seafood - - All Gender - - 27 - - 26.82 - - 69.49 -
      - Sunday Paper - - Snack Foods - - All Gender - - 469 - - 413.18 - - 1,027.98 -
      - Sunday Paper - - Snacks - - All Gender - - 123 - - 108.50 - - 261.38 -
      - Sunday Paper - - Starchy Foods - - All Gender - - 109 - - 108.91 - - 266.75 -
      - Sunday Paper - - Non-Consumable - - All Gender - - 803 - - 681.86 - - 1,676.70 -
      - Sunday Paper - - Carousel - - All Gender - - 7 - - 6.70 - - 14.68 -
      - Sunday Paper - - Checkout - - All Gender - - 17 - - 13.09 - - 30.89 -
      - Sunday Paper - - Health and Hygiene - - All Gender - - 278 - - 227.06 - - 565.99 -
      - Sunday Paper - - Household - - All Gender - - 420 - - 371.58 - - 911.69 -
      - Sunday Paper - - Periodicals - - All Gender - - 81 - - 63.43 - - 153.45 -
      - Sunday Paper, Radio - - All Products - - All Gender - - 5,945 - - 5,027.31 - - 12,551.96 -
      - Sunday Paper, Radio - - Drink - - All Gender - - 591 - - 454.03 - - 1,129.94 -
      - Sunday Paper, Radio - - Food - - All Gender - - 4,239 - - 3,612.38 - - 9,033.23 -
      - Sunday Paper, Radio - - Baked Goods - - All Gender - - 152 - - 109.11 - - 274.39 -
      - Sunday Paper, Radio - - Baking Goods - - All Gender - - 482 - - 367.13 - - 913.84 -
      - Sunday Paper, Radio - - Baking Goods - - All Gender - - 206 - - 152.72 - - 381.59 -
      - Sunday Paper, Radio - - Jams and Jellies - - All Gender - - 276 - - 214.41 - - 532.25 -
      - Sunday Paper, Radio - - Jam - - All Gender - - 52 - - 52.39 - - 126.62 -
      - Sunday Paper, Radio - - Jelly - - All Gender - - 74 - - 53.93 - - 135.03 -
      - Sunday Paper, Radio - - Peanut Butter - - All Gender - - 64 - - 50.10 - - 126.71 -
      - Sunday Paper, Radio - - BBB Best - - All Gender - - 14 - - 11.58 - - 27.40 -
      - Sunday Paper, Radio - - CDR - - All Gender - - 17 - - 14.68 - - 41.25 -
      - Sunday Paper, Radio - - Landslide - - All Gender - - 14 - - 6.62 - - 17.04 -
      - Sunday Paper, Radio - - Plato - - All Gender - - 7 - - 6.91 - - 17.15 -
      - Sunday Paper, Radio - - Super - - All Gender - - 12 - - 10.31 - - 23.87 -
      - Sunday Paper, Radio - - Preserves - - All Gender - - 86 - - 57.99 - - 143.89 -
      - Sunday Paper, Radio - - Breakfast Foods - - All Gender - - 80 - - 62.80 - - 154.04 -
      - Sunday Paper, Radio - - Canned Foods - - All Gender - - 456 - - 361.79 - - 914.81 -
      - Sunday Paper, Radio - - Canned Products - - All Gender - - 45 - - 39.72 - - 95.88 -
      - Sunday Paper, Radio - - Dairy - - All Gender - - 283 - - 296.91 - - 722.75 -
      - Sunday Paper, Radio - - Deli - - All Gender - - 252 - - 190.32 - - 479.59 -
      - Sunday Paper, Radio - - Eggs - - All Gender - - 114 - - 104.65 - - 256.15 -
      - Sunday Paper, Radio - - Frozen Foods - - All Gender - - 599 - - 490.33 - - 1,222.54 -
      - Sunday Paper, Radio - - Meat - - All Gender - - 40 - - 31.66 - - 84.76 -
      - Sunday Paper, Radio - - Produce - - All Gender - - 858 - - 752.62 - - 1,886.01 -
      - Sunday Paper, Radio - - Seafood - - All Gender - - 27 - - 20.66 - - 50.39 -
      - Sunday Paper, Radio - - Snack Foods - - All Gender - - 596 - - 555.70 - - 1,402.21 -
      - Sunday Paper, Radio - - Snacks - - All Gender - - 147 - - 120.43 - - 304.18 -
      - Sunday Paper, Radio - - Starchy Foods - - All Gender - - 108 - - 108.55 - - 271.69 -
      - Sunday Paper, Radio - - Non-Consumable - - All Gender - - 1,115 - - 960.90 - - 2,388.79 -
      - Sunday Paper, Radio - - Carousel - - All Gender - - 18 - - 10.99 - - 26.94 -
      - Sunday Paper, Radio - - Checkout - - All Gender - - 26 - - 24.68 - - 62.14 -
      - Sunday Paper, Radio - - Health and Hygiene - - All Gender - - 378 - - 309.37 - - 771.48 -
      - Sunday Paper, Radio - - Household - - All Gender - - 585 - - 516.99 - - 1,276.16 -
      - Sunday Paper, Radio - - Periodicals - - All Gender - - 108 - - 98.86 - - 252.07 -
      - Sunday Paper, Radio, TV - - All Products - - All Gender - - 2,726 - - 2,341.58 - - 5,819.33 -
      - Sunday Paper, Radio, TV - - Drink - - All Gender - - 225 - - 163.09 - - 403.51 -
      - Sunday Paper, Radio, TV - - Food - - All Gender - - 2,021 - - 1,762.18 - - 4,377.85 -
      - Sunday Paper, Radio, TV - - Baked Goods - - All Gender - - 67 - - 66.17 - - 163.29 -
      - Sunday Paper, Radio, TV - - Baking Goods - - All Gender - - 228 - - 182.98 - - 455.90 -
      - Sunday Paper, Radio, TV - - Baking Goods - - All Gender - - 90 - - 73.09 - - 176.63 -
      - Sunday Paper, Radio, TV - - Jams and Jellies - - All Gender - - 138 - - 109.90 - - 279.27 -
      - Sunday Paper, Radio, TV - - Jam - - All Gender - - 37 - - 31.30 - - 78.56 -
      - Sunday Paper, Radio, TV - - Jelly - - All Gender - - 27 - - 16.18 - - 39.92 -
      - Sunday Paper, Radio, TV - - Peanut Butter - - All Gender - - 30 - - 24.01 - - 64.19 -
      - Sunday Paper, Radio, TV - - BBB Best - - All Gender - - 11 - - 9.78 - - 23.86 -
      - Sunday Paper, Radio, TV - - CDR - - All Gender - -   - -   - -   -
      - Sunday Paper, Radio, TV - - Landslide - - All Gender - - 4 - - 2.39 - - 5.68 -
      - Sunday Paper, Radio, TV - - Plato - - All Gender - - 5 - - 3.85 - - 11.60 -
      - Sunday Paper, Radio, TV - - Super - - All Gender - - 10 - - 7.99 - - 23.05 -
      - Sunday Paper, Radio, TV - - Preserves - - All Gender - - 44 - - 38.41 - - 96.60 -
      - Sunday Paper, Radio, TV - - Breakfast Foods - - All Gender - - 38 - - 32.76 - - 89.85 -
      - Sunday Paper, Radio, TV - - Canned Foods - - All Gender - - 180 - - 138.77 - - 340.04 -
      - Sunday Paper, Radio, TV - - Canned Products - - All Gender - - 14 - - 12.00 - - 28.28 -
      - Sunday Paper, Radio, TV - - Dairy - - All Gender - - 121 - - 125.32 - - 305.43 -
      - Sunday Paper, Radio, TV - - Deli - - All Gender - - 131 - - 98.93 - - 245.42 -
      - Sunday Paper, Radio, TV - - Eggs - - All Gender - - 39 - - 39.57 - - 91.99 -
      - Sunday Paper, Radio, TV - - Frozen Foods - - All Gender - - 279 - - 207.59 - - 514.95 -
      - Sunday Paper, Radio, TV - - Meat - - All Gender - - 12 - - 11.77 - - 30.23 -
      - Sunday Paper, Radio, TV - - Produce - - All Gender - - 411 - - 382.14 - - 943.93 -
      - Sunday Paper, Radio, TV - - Seafood - - All Gender - - 31 - - 28.07 - - 69.82 -
      - Sunday Paper, Radio, TV - - Snack Foods - - All Gender - - 346 - - 318.26 - - 798.50 -
      - Sunday Paper, Radio, TV - - Snacks - - All Gender - - 75 - - 65.49 - - 174.02 -
      - Sunday Paper, Radio, TV - - Starchy Foods - - All Gender - - 49 - - 52.37 - - 126.20 -
      - Sunday Paper, Radio, TV - - Non-Consumable - - All Gender - - 480 - - 416.30 - - 1,037.97 -
      - Sunday Paper, Radio, TV - - Carousel - - All Gender - - 21 - - 11.63 - - 27.92 -
      - Sunday Paper, Radio, TV - - Checkout - - All Gender - - 10 - - 8.12 - - 19.80 -
      - Sunday Paper, Radio, TV - - Health and Hygiene - - All Gender - - 138 - - 110.35 - - 276.31 -
      - Sunday Paper, Radio, TV - - Household - - All Gender - - 262 - - 244.90 - - 608.52 -
      - Sunday Paper, Radio, TV - - Periodicals - - All Gender - - 49 - - 41.30 - - 105.42 -
      - TV - - All Products - - All Gender - - 3,607 - - 3,116.40 - - 7,786.21 -
      - TV - - Drink - - All Gender - - 332 - - 283.18 - - 721.07 -
      - TV - - Food - - All Gender - - 2,563 - - 2,238.13 - - 5,573.27 -
      - TV - - Baked Goods - - All Gender - - 114 - - 103.40 - - 262.97 -
      - TV - - Baking Goods - - All Gender - - 237 - - 185.55 - - 464.23 -
      - TV - - Baking Goods - - All Gender - - 95 - - 74.29 - - 190.59 -
      - TV - - Jams and Jellies - - All Gender - - 142 - - 111.25 - - 273.64 -
      - TV - - Jam - - All Gender - - 38 - - 32.28 - - 77.58 -
      - TV - - Jelly - - All Gender - - 35 - - 24.64 - - 63.38 -
      - TV - - Peanut Butter - - All Gender - - 31 - - 21.83 - - 56.80 -
      - TV - - BBB Best - - All Gender - -   - -   - -   -
      - TV - - CDR - - All Gender - - 11 - - 9.78 - - 27.19 -
      - TV - - Landslide - - All Gender - - 7 - - 2.61 - - 7.12 -
      - TV - - Plato - - All Gender - - 6 - - 4.95 - - 12.13 -
      - TV - - Super - - All Gender - - 7 - - 4.48 - - 10.36 -
      - TV - - Preserves - - All Gender - - 38 - - 32.51 - - 75.88 -
      - TV - - Breakfast Foods - - All Gender - - 36 - - 30.11 - - 79.89 -
      - TV - - Canned Foods - - All Gender - - 240 - - 200.00 - - 519.91 -
      - TV - - Canned Products - - All Gender - - 26 - - 15.00 - - 38.65 -
      - TV - - Dairy - - All Gender - - 179 - - 183.73 - - 458.87 -
      - TV - - Deli - - All Gender - - 155 - - 139.76 - - 342.51 -
      - TV - - Eggs - - All Gender - - 42 - - 32.74 - - 80.93 -
      - TV - - Frozen Foods - - All Gender - - 352 - - 300.42 - - 738.40 -
      - TV - - Meat - - All Gender - - 22 - - 19.76 - - 49.27 -
      - TV - - Produce - - All Gender - - 543 - - 456.53 - - 1,145.45 -
      - TV - - Seafood - - All Gender - - 34 - - 30.71 - - 75.47 -
      - TV - - Snack Foods - - All Gender - - 401 - - 377.01 - - 927.50 -
      - TV - - Snacks - - All Gender - - 99 - - 92.80 - - 220.54 -
      - TV - - Starchy Foods - - All Gender - - 83 - - 70.61 - - 168.68 -
      - TV - - Non-Consumable - - All Gender - - 712 - - 595.08 - - 1,491.87 -
      - TV - - Carousel - - All Gender - - 4 - - 3.13 - - 9.20 -
      - TV - - Checkout - - All Gender - - 34 - - 34.12 - - 86.21 -
      - TV - - Health and Hygiene - - All Gender - - 249 - - 196.08 - - 486.46 -
      - TV - - Household - - All Gender - - 361 - - 316.09 - - 795.40 -
      - TV - - Periodicals - - All Gender - - 64 - - 45.67 - - 114.60 -
      +   + + Measures + + Measures + + Measures +
      + Promotion Media + + Product + + Gender + + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + All Products + + All Gender + + 266,773 + + 225,627.23 + + 565,238.13 +
      + All Media + + Drink + + All Gender + + 24,597 + + 19,477.23 + + 48,836.21 +
      + All Media + + Food + + All Gender + + 191,940 + + 163,270.72 + + 409,035.59 +
      + All Media + + Baked Goods + + All Gender + + 7,870 + + 6,564.09 + + 16,455.43 +
      + All Media + + Baking Goods + + All Gender + + 20,245 + + 15,370.61 + + 38,670.41 +
      + All Media + + Baking Goods + + All Gender + + 8,357 + + 6,123.32 + + 15,446.69 +
      + All Media + + Baking Goods + + F + + 4,005 + + 2,907.70 + + 7,313.61 +
      + All Media + + Baking Goods + + M + + 4,352 + + 3,215.62 + + 8,133.08 +
      + All Media + + Jams and Jellies + + All Gender + + 11,888 + + 9,247.29 + + 23,223.72 +
      + All Media + + Jam + + All Gender + + 2,556 + + 2,132.27 + + 5,401.81 +
      + All Media + + Jelly + + All Gender + + 2,565 + + 1,830.04 + + 4,609.61 +
      + All Media + + Jelly + + F + + 1,309 + + 956.94 + + 2,414.94 +
      + All Media + + Jelly + + M + + 1,256 + + 873.10 + + 2,194.67 +
      + All Media + + Peanut Butter + + All Gender + + 2,667 + + 2,097.37 + + 5,231.08 +
      + All Media + + BBB Best + + All Gender + + 556 + + 424.38 + + 1,055.72 +
      + All Media + + BBB Best + + F + + 271 + + 201.08 + + 500.39 +
      + All Media + + BBB Best + + M + + 285 + + 223.30 + + 555.33 +
      + All Media + + BBB Best Chunky Peanut Butter + + All Gender + + 188 + + 147.32 + + 370.36 +
      + All Media + + BBB Best Chunky Peanut Butter + + F + + 107 + + 85.81 + + 210.79 +
      + All Media + + BBB Best Chunky Peanut Butter + + M + + 81 + + 61.50 + + 159.57 +
      + All Media + + BBB Best Creamy Peanut Butter + + All Gender + + 201 + + 87.86 + + 221.10 +
      + All Media + + BBB Best Creamy Peanut Butter + + F + + 99 + + 43.35 + + 108.90 +
      + All Media + + BBB Best Creamy Peanut Butter + + M + + 102 + + 44.51 + + 112.20 +
      + All Media + + BBB Best Extra Chunky Peanut Butter + + All Gender + + 167 + + 189.21 + + 464.26 +
      + All Media + + BBB Best Extra Chunky Peanut Butter + + F + + 65 + + 71.92 + + 180.70 +
      + All Media + + BBB Best Extra Chunky Peanut Butter + + M + + 102 + + 117.29 + + 283.56 +
      + All Media + + CDR + + All Gender + + 545 + + 538.88 + + 1,326.30 +
      + All Media + + Landslide + + All Gender + + 531 + + 256.16 + + 635.29 +
      + All Media + + Plato + + All Gender + + 520 + + 447.73 + + 1,132.16 +
      + All Media + + Super + + All Gender + + 515 + + 430.21 + + 1,081.61 +
      + All Media + + Preserves + + All Gender + + 4,100 + + 3,187.61 + + 7,981.22 +
      + All Media + + Preserves + + F + + 1,946 + + 1,472.42 + + 3,717.80 +
      + All Media + + Preserves + + M + + 2,154 + + 1,715.19 + + 4,263.42 +
      + All Media + + Breakfast Foods + + All Gender + + 3,317 + + 2,756.80 + + 6,941.46 +
      + All Media + + Canned Foods + + All Gender + + 19,026 + + 15,894.53 + + 39,774.34 +
      + All Media + + Canned Anchovies + + All Gender + + 900 + + 913.88 + + 2,296.38 +
      + All Media + + Canned Clams + + All Gender + + 882 + + 759.80 + + 1,912.68 +
      + All Media + + Clams + + All Gender + + 882 + + 759.80 + + 1,912.68 +
      + All Media + + Better + + All Gender + + 189 + + 151.14 + + 398.79 +
      + All Media + + Blue Label + + All Gender + + 165 + + 112.82 + + 278.85 +
      + All Media + + Bravo + + All Gender + + 184 + + 280.70 + + 708.40 +
      + All Media + + Just Right + + All Gender + + 177 + + 161.96 + + 394.71 +
      + All Media + + Pleasant + + All Gender + + 167 + + 53.17 + + 131.93 +
      + All Media + + Canned Oysters + + All Gender + + 708 + + 571.50 + + 1,442.77 +
      + All Media + + Canned Sardines + + All Gender + + 819 + + 537.59 + + 1,357.80 +
      + All Media + + Canned Shrimp + + All Gender + + 804 + + 858.39 + + 2,146.49 +
      + All Media + + Canned Soup + + All Gender + + 8,006 + + 6,408.29 + + 15,966.10 +
      + All Media + + Canned Tuna + + All Gender + + 1,710 + + 1,288.52 + + 3,210.76 +
      + All Media + + Vegetables + + All Gender + + 5,197 + + 4,556.57 + + 11,441.36 +
      + All Media + + Canned Products + + All Gender + + 1,812 + + 1,317.13 + + 3,314.52 +
      + All Media + + Dairy + + All Gender + + 12,885 + + 12,228.85 + + 30,508.85 +
      + All Media + + Deli + + All Gender + + 12,037 + + 10,108.87 + + 25,318.93 +
      + All Media + + Meat + + All Gender + + 9,433 + + 8,215.81 + + 20,616.29 +
      + All Media + + Bologna + + All Gender + + 2,588 + + 2,340.24 + + 5,859.95 +
      + All Media + + Deli Meats + + All Gender + + 3,339 + + 2,851.18 + + 7,191.24 +
      + All Media + + Deli Meats + + F + + 1,653 + + 1,414.49 + + 3,579.34 +
      + All Media + + Deli Meats + + M + + 1,686 + + 1,436.69 + + 3,611.90 +
      + All Media + + Fresh Chicken + + All Gender + + 878 + + 842.85 + + 2,091.52 +
      + All Media + + Hot Dogs + + All Gender + + 2,628 + + 2,181.55 + + 5,473.58 +
      + All Media + + Side Dishes + + All Gender + + 2,604 + + 1,893.06 + + 4,702.64 +
      + All Media + + Eggs + + All Gender + + 4,132 + + 3,684.90 + + 9,200.76 +
      + All Media + + Frozen Foods + + All Gender + + 26,655 + + 22,030.66 + + 55,207.50 +
      + All Media + + Meat + + All Gender + + 1,714 + + 1,465.42 + + 3,669.89 +
      + All Media + + Produce + + All Gender + + 37,792 + + 32,831.33 + + 82,248.42 +
      + All Media + + Seafood + + All Gender + + 1,764 + + 1,520.70 + + 3,809.14 +
      + All Media + + Snack Foods + + All Gender + + 30,545 + + 26,963.34 + + 67,609.82 +
      + All Media + + Snacks + + All Gender + + 6,884 + + 5,827.58 + + 14,550.05 +
      + All Media + + Starchy Foods + + All Gender + + 5,262 + + 4,705.91 + + 11,756.07 +
      + All Media + + Non-Consumable + + All Gender + + 50,236 + + 42,879.28 + + 107,366.33 +
      + All Media + + Carousel + + All Gender + + 841 + + 595.97 + + 1,500.11 +
      + All Media + + Checkout + + All Gender + + 1,779 + + 1,525.04 + + 3,767.71 +
      + All Media + + Health and Hygiene + + All Gender + + 16,284 + + 12,972.99 + + 32,571.86 +
      + All Media + + Household + + All Gender + + 27,038 + + 24,170.73 + + 60,469.89 +
      + All Media + + Periodicals + + All Gender + + 4,294 + + 3,614.55 + + 9,056.76 +
      + Bulk Mail + + All Products + + All Gender + + 4,320 + + 3,740.95 + + 9,349.07 +
      + Cash Register Handout + + All Products + + All Gender + + 6,697 + + 5,715.67 + + 14,321.33 +
      + Daily Paper + + All Products + + All Gender + + 7,738 + + 6,559.23 + + 16,479.81 +
      + Daily Paper, Radio + + All Products + + All Gender + + 6,891 + + 5,668.77 + + 14,169.42 +
      + Daily Paper, Radio, TV + + All Products + + All Gender + + 9,513 + + 8,055.22 + + 20,173.97 +
      + In-Store Coupon + + All Products + + All Gender + + 3,798 + + 3,263.11 + + 8,162.46 +
      + In-Store Coupon + + Drink + + All Gender + + 345 + + 282.44 + + 708.38 +
      + In-Store Coupon + + Food + + All Gender + + 2,737 + + 2,345.57 + + 5,889.34 +
      + In-Store Coupon + + Baked Goods + + All Gender + + 131 + + 114.11 + + 279.11 +
      + In-Store Coupon + + Baking Goods + + All Gender + + 308 + + 252.88 + + 632.01 +
      + In-Store Coupon + + Baking Goods + + All Gender + + 146 + + 103.30 + + 261.44 +
      + In-Store Coupon + + Jams and Jellies + + All Gender + + 162 + + 149.58 + + 370.57 +
      + In-Store Coupon + + Jam + + All Gender + + 55 + + 58.16 + + 141.19 +
      + In-Store Coupon + + Jelly + + All Gender + + 32 + + 23.96 + + 62.12 +
      + In-Store Coupon + + Peanut Butter + + All Gender + + 22 + + 19.54 + + 48.72 +
      + In-Store Coupon + + BBB Best + + All Gender + + 7 + + 6.72 + + 16.10 +
      + In-Store Coupon + + CDR + + All Gender + + 10 + + 9.81 + + 24.32 +
      + In-Store Coupon + + Landslide + + All Gender + +   + +   + +   +
      + In-Store Coupon + + Plato + + All Gender + + 3 + + 2.32 + + 6.32 +
      + In-Store Coupon + + Super + + All Gender + + 2 + + .69 + + 1.98 +
      + In-Store Coupon + + Preserves + + All Gender + + 53 + + 47.92 + + 118.54 +
      + In-Store Coupon + + Breakfast Foods + + All Gender + + 59 + + 49.22 + + 125.19 +
      + In-Store Coupon + + Breakfast Foods + + F + + 33 + + 22.88 + + 54.84 +
      + In-Store Coupon + + Breakfast Foods + + M + + 26 + + 26.34 + + 70.35 +
      + In-Store Coupon + + Canned Foods + + All Gender + + 245 + + 200.61 + + 506.67 +
      + In-Store Coupon + + Canned Products + + All Gender + + 15 + + 9.58 + + 26.17 +
      + In-Store Coupon + + Dairy + + All Gender + + 166 + + 153.42 + + 372.01 +
      + In-Store Coupon + + Deli + + All Gender + + 180 + + 163.58 + + 392.68 +
      + In-Store Coupon + + Eggs + + All Gender + + 56 + + 42.51 + + 108.90 +
      + In-Store Coupon + + Frozen Foods + + All Gender + + 374 + + 301.63 + + 773.52 +
      + In-Store Coupon + + Meat + + All Gender + + 31 + + 23.91 + + 70.35 +
      + In-Store Coupon + + Produce + + All Gender + + 563 + + 499.63 + + 1,257.05 +
      + In-Store Coupon + + Seafood + + All Gender + + 34 + + 30.06 + + 76.09 +
      + In-Store Coupon + + Snack Foods + + All Gender + + 439 + + 390.35 + + 989.13 +
      + In-Store Coupon + + Snacks + + All Gender + + 78 + + 63.77 + + 153.02 +
      + In-Store Coupon + + Starchy Foods + + All Gender + + 58 + + 50.30 + + 127.44 +
      + In-Store Coupon + + Non-Consumable + + All Gender + + 716 + + 635.10 + + 1,564.74 +
      + In-Store Coupon + + Carousel + + All Gender + + 17 + + 8.77 + + 24.18 +
      + In-Store Coupon + + Checkout + + All Gender + + 23 + + 15.20 + + 40.19 +
      + In-Store Coupon + + Health and Hygiene + + All Gender + + 251 + + 193.53 + + 477.21 +
      + In-Store Coupon + + Household + + All Gender + + 374 + + 375.66 + + 916.97 +
      + In-Store Coupon + + Periodicals + + All Gender + + 51 + + 41.94 + + 106.19 +
      + No Media + + All Products + + All Gender + + 195,448 + + 165,214.85 + + 414,026.92 +
      + No Media + + Drink + + All Gender + + 17,896 + + 14,211.41 + + 35,681.85 +
      + No Media + + Food + + All Gender + + 140,577 + + 119,469.36 + + 299,356.11 +
      + No Media + + Baked Goods + + All Gender + + 5,753 + + 4,775.86 + + 11,972.46 +
      + No Media + + Baking Goods + + All Gender + + 14,849 + + 11,226.15 + + 28,312.78 +
      + No Media + + Baking Goods + + All Gender + + 5,979 + + 4,347.34 + + 11,002.73 +
      + No Media + + Jams and Jellies + + All Gender + + 8,870 + + 6,878.81 + + 17,310.05 +
      + No Media + + Jam + + All Gender + + 1,883 + + 1,554.13 + + 3,965.74 +
      + No Media + + Jelly + + All Gender + + 1,936 + + 1,394.32 + + 3,504.71 +
      + No Media + + Peanut Butter + + All Gender + + 1,984 + + 1,534.19 + + 3,828.01 +
      + No Media + + BBB Best + + All Gender + + 406 + + 293.97 + + 735.29 +
      + No Media + + CDR + + All Gender + + 411 + + 401.88 + + 998.12 +
      + No Media + + Landslide + + All Gender + + 401 + + 195.51 + + 478.44 +
      + No Media + + Plato + + All Gender + + 384 + + 331.26 + + 832.92 +
      + No Media + + Super + + All Gender + + 382 + + 311.57 + + 783.24 +
      + No Media + + Preserves + + All Gender + + 3,067 + + 2,396.16 + + 6,011.59 +
      + No Media + + Breakfast Foods + + All Gender + + 2,418 + + 1,996.45 + + 5,016.10 +
      + No Media + + Canned Foods + + All Gender + + 13,861 + + 11,647.47 + + 29,102.79 +
      + No Media + + Canned Products + + All Gender + + 1,344 + + 960.82 + + 2,424.98 +
      + No Media + + Dairy + + All Gender + + 9,510 + + 8,981.13 + + 22,454.02 +
      + No Media + + Deli + + All Gender + + 8,695 + + 7,353.56 + + 18,410.26 +
      + No Media + + Eggs + + All Gender + + 2,976 + + 2,640.47 + + 6,606.25 +
      + No Media + + Frozen Foods + + All Gender + + 19,450 + + 16,127.24 + + 40,411.08 +
      + No Media + + Meat + + All Gender + + 1,236 + + 1,068.07 + + 2,646.00 +
      + No Media + + Produce + + All Gender + + 27,637 + + 24,036.36 + + 60,203.58 +
      + No Media + + Seafood + + All Gender + + 1,292 + + 1,114.69 + + 2,774.43 +
      + No Media + + Snack Foods + + All Gender + + 22,525 + + 19,800.82 + + 49,680.71 +
      + No Media + + Snacks + + All Gender + + 5,100 + + 4,264.55 + + 10,690.26 +
      + No Media + + Starchy Foods + + All Gender + + 3,931 + + 3,475.74 + + 8,650.41 +
      + No Media + + Non-Consumable + + All Gender + + 36,975 + + 31,534.08 + + 78,988.96 +
      + No Media + + Carousel + + All Gender + + 584 + + 419.65 + + 1,050.75 +
      + No Media + + Checkout + + All Gender + + 1,305 + + 1,113.97 + + 2,768.66 +
      + No Media + + Health and Hygiene + + All Gender + + 11,845 + + 9,413.25 + + 23,621.12 +
      + No Media + + Household + + All Gender + + 20,091 + + 17,929.20 + + 44,881.13 +
      + No Media + + Periodicals + + All Gender + + 3,150 + + 2,658.00 + + 6,667.30 +
      + Product Attachment + + All Products + + All Gender + + 7,544 + + 6,306.24 + + 15,898.25 +
      + Product Attachment + + Drink + + All Gender + + 713 + + 555.05 + + 1,403.65 +
      + Product Attachment + + Food + + All Gender + + 5,441 + + 4,571.71 + + 11,525.25 +
      + Product Attachment + + Baked Goods + + All Gender + + 213 + + 175.69 + + 445.60 +
      + Product Attachment + + Baking Goods + + All Gender + + 547 + + 410.31 + + 1,032.59 +
      + Product Attachment + + Baking Goods + + All Gender + + 258 + + 191.48 + + 470.58 +
      + Product Attachment + + Jams and Jellies + + All Gender + + 289 + + 218.83 + + 562.01 +
      + Product Attachment + + Jam + + All Gender + + 66 + + 48.03 + + 128.68 +
      + Product Attachment + + Jelly + + All Gender + + 45 + + 34.12 + + 90.62 +
      + Product Attachment + + Peanut Butter + + All Gender + + 63 + + 47.71 + + 122.31 +
      + Product Attachment + + BBB Best + + All Gender + + 15 + + 14.53 + + 38.46 +
      + Product Attachment + + CDR + + All Gender + + 13 + + 11.94 + + 30.57 +
      + Product Attachment + + Landslide + + All Gender + + 12 + + 5.32 + + 14.28 +
      + Product Attachment + + Plato + + All Gender + + 9 + + 7.16 + + 17.43 +
      + Product Attachment + + Super + + All Gender + + 14 + + 8.75 + + 21.57 +
      + Product Attachment + + Preserves + + All Gender + + 115 + + 88.98 + + 220.40 +
      + Product Attachment + + Breakfast Foods + + All Gender + + 103 + + 87.35 + + 220.75 +
      + Product Attachment + + Canned Foods + + All Gender + + 564 + + 463.28 + + 1,154.91 +
      + Product Attachment + + Canned Products + + All Gender + + 60 + + 51.61 + + 124.24 +
      + Product Attachment + + Dairy + + All Gender + + 355 + + 339.81 + + 849.78 +
      + Product Attachment + + Deli + + All Gender + + 324 + + 243.64 + + 618.23 +
      + Product Attachment + + Eggs + + All Gender + + 118 + + 97.43 + + 241.21 +
      + Product Attachment + + Frozen Foods + + All Gender + + 812 + + 665.48 + + 1,692.11 +
      + Product Attachment + + Meat + + All Gender + + 54 + + 51.36 + + 127.83 +
      + Product Attachment + + Produce + + All Gender + + 1,069 + + 909.24 + + 2,287.61 +
      + Product Attachment + + Seafood + + All Gender + + 45 + + 36.98 + + 100.61 +
      + Product Attachment + + Snack Foods + + All Gender + + 819 + + 726.73 + + 1,847.28 +
      + Product Attachment + + Snacks + + All Gender + + 209 + + 186.22 + + 450.03 +
      + Product Attachment + + Starchy Foods + + All Gender + + 149 + + 126.59 + + 332.47 +
      + Product Attachment + + Non-Consumable + + All Gender + + 1,390 + + 1,179.48 + + 2,969.35 +
      + Product Attachment + + Carousel + + All Gender + + 14 + + 7.99 + + 21.21 +
      + Product Attachment + + Checkout + + All Gender + + 48 + + 40.45 + + 100.61 +
      + Product Attachment + + Health and Hygiene + + All Gender + + 440 + + 356.54 + + 901.73 +
      + Product Attachment + + Household + + All Gender + + 777 + + 690.03 + + 1,737.96 +
      + Product Attachment + + Periodicals + + All Gender + + 111 + + 84.48 + + 207.84 +
      + Radio + + All Products + + All Gender + + 2,454 + + 2,087.51 + + 5,213.61 +
      + Radio + + Drink + + All Gender + + 226 + + 182.85 + + 443.68 +
      + Radio + + Food + + All Gender + + 1,733 + + 1,485.25 + + 3,727.36 +
      + Radio + + Baked Goods + + All Gender + + 83 + + 76.51 + + 186.20 +
      + Radio + + Baking Goods + + All Gender + + 157 + + 109.10 + + 274.90 +
      + Radio + + Baking Goods + + All Gender + + 63 + + 45.02 + + 110.43 +
      + Radio + + Jams and Jellies + + All Gender + + 94 + + 64.08 + + 164.47 +
      + Radio + + Jam + + All Gender + + 15 + + 10.42 + + 26.94 +
      + Radio + + Jelly + + All Gender + + 24 + + 14.54 + + 37.49 +
      + Radio + + Peanut Butter + + All Gender + + 19 + + 16.85 + + 41.82 +
      + Radio + + BBB Best + + All Gender + + 10 + + 10.58 + + 24.44 +
      + Radio + + CDR + + All Gender + +   + +   + +   +
      + Radio + + Landslide + + All Gender + +   + +   + +   +
      + Radio + + Plato + + All Gender + + 4 + + 3.77 + + 9.80 +
      + Radio + + Super + + All Gender + + 5 + + 2.50 + + 7.58 +
      + Radio + + Preserves + + All Gender + + 36 + + 22.28 + + 58.22 +
      + Radio + + Breakfast Foods + + All Gender + + 25 + + 18.78 + + 50.22 +
      + Radio + + Canned Foods + + All Gender + + 158 + + 124.79 + + 307.55 +
      + Radio + + Canned Products + + All Gender + + 22 + + 17.29 + + 43.42 +
      + Radio + + Dairy + + All Gender + + 112 + + 92.12 + + 216.79 +
      + Radio + + Deli + + All Gender + + 129 + + 119.14 + + 307.25 +
      + Radio + + Eggs + + All Gender + + 25 + + 29.97 + + 71.15 +
      + Radio + + Frozen Foods + + All Gender + + 253 + + 202.71 + + 507.45 +
      + Radio + + Meat + + All Gender + + 12 + + 11.53 + + 32.85 +
      + Radio + + Produce + + All Gender + + 336 + + 292.05 + + 738.20 +
      + Radio + + Seafood + + All Gender + + 15 + + 13.28 + + 35.58 +
      + Radio + + Snack Foods + + All Gender + + 290 + + 270.59 + + 674.73 +
      + Radio + + Snacks + + All Gender + + 60 + + 55.67 + + 144.58 +
      + Radio + + Starchy Foods + + All Gender + + 56 + + 51.72 + + 136.49 +
      + Radio + + Non-Consumable + + All Gender + + 495 + + 419.41 + + 1,042.57 +
      + Radio + + Carousel + + All Gender + + 15 + + 11.15 + + 26.85 +
      + Radio + + Checkout + + All Gender + + 21 + + 17.00 + + 42.74 +
      + Radio + + Health and Hygiene + + All Gender + + 145 + + 114.84 + + 289.80 +
      + Radio + + Household + + All Gender + + 258 + + 233.31 + + 575.07 +
      + Radio + + Periodicals + + All Gender + + 56 + + 43.12 + + 108.11 +
      + Street Handout + + All Products + + All Gender + + 5,753 + + 4,856.54 + + 12,192.90 +
      + Street Handout + + Drink + + All Gender + + 512 + + 372.68 + + 943.42 +
      + Street Handout + + Food + + All Gender + + 4,239 + + 3,650.32 + + 9,151.65 +
      + Street Handout + + Baked Goods + + All Gender + + 160 + + 120.12 + + 301.62 +
      + Street Handout + + Baking Goods + + All Gender + + 498 + + 373.67 + + 923.22 +
      + Street Handout + + Baking Goods + + All Gender + + 200 + + 144.16 + + 357.82 +
      + Street Handout + + Jams and Jellies + + All Gender + + 298 + + 229.51 + + 565.40 +
      + Street Handout + + Jam + + All Gender + + 53 + + 44.30 + + 112.95 +
      + Street Handout + + Jelly + + All Gender + + 92 + + 63.14 + + 155.59 +
      + Street Handout + + Peanut Butter + + All Gender + + 51 + + 51.06 + + 118.90 +
      + Street Handout + + BBB Best + + All Gender + + 11 + + 10.85 + + 25.72 +
      + Street Handout + + CDR + + All Gender + + 8 + + 9.06 + + 19.73 +
      + Street Handout + + Landslide + + All Gender + + 11 + + 6.90 + + 15.54 +
      + Street Handout + + Plato + + All Gender + + 9 + + 8.47 + + 20.89 +
      + Street Handout + + Super + + All Gender + + 12 + + 15.78 + + 37.02 +
      + Street Handout + + Preserves + + All Gender + + 102 + + 71.02 + + 177.96 +
      + Street Handout + + Breakfast Foods + + All Gender + + 81 + + 74.32 + + 192.90 +
      + Street Handout + + Canned Foods + + All Gender + + 459 + + 413.21 + + 1,021.86 +
      + Street Handout + + Canned Products + + All Gender + + 30 + + 19.43 + + 45.68 +
      + Street Handout + + Dairy + + All Gender + + 301 + + 285.98 + + 718.61 +
      + Street Handout + + Deli + + All Gender + + 305 + + 253.54 + + 638.30 +
      + Street Handout + + Eggs + + All Gender + + 66 + + 59.15 + + 156.82 +
      + Street Handout + + Frozen Foods + + All Gender + + 612 + + 520.12 + + 1,313.71 +
      + Street Handout + + Meat + + All Gender + + 37 + + 29.82 + + 78.24 +
      + Street Handout + + Produce + + All Gender + + 745 + + 662.39 + + 1,639.94 +
      + Street Handout + + Seafood + + All Gender + + 37 + + 30.12 + + 72.77 +
      + Street Handout + + Snack Foods + + All Gender + + 675 + + 600.23 + + 1,515.68 +
      + Street Handout + + Snacks + + All Gender + + 144 + + 128.79 + + 321.16 +
      + Street Handout + + Starchy Foods + + All Gender + + 89 + + 79.43 + + 211.14 +
      + Street Handout + + Non-Consumable + + All Gender + + 1,002 + + 833.53 + + 2,097.83 +
      + Street Handout + + Carousel + + All Gender + + 17 + + 13.53 + + 30.98 +
      + Street Handout + + Checkout + + All Gender + + 45 + + 34.77 + + 85.38 +
      + Street Handout + + Health and Hygiene + + All Gender + + 402 + + 318.03 + + 802.92 +
      + Street Handout + + Household + + All Gender + + 501 + + 436.41 + + 1,105.38 +
      + Street Handout + + Periodicals + + All Gender + + 37 + + 30.80 + + 73.17 +
      + Sunday Paper + + All Products + + All Gender + + 4,339 + + 3,673.86 + + 9,092.89 +
      + Sunday Paper + + Drink + + All Gender + + 430 + + 345.53 + + 856.73 +
      + Sunday Paper + + Food + + All Gender + + 3,106 + + 2,646.47 + + 6,559.46 +
      + Sunday Paper + + Baked Goods + + All Gender + + 140 + + 110.79 + + 282.55 +
      + Sunday Paper + + Baking Goods + + All Gender + + 338 + + 239.76 + + 603.86 +
      + Sunday Paper + + Baking Goods + + All Gender + + 170 + + 118.05 + + 298.79 +
      + Sunday Paper + + Jams and Jellies + + All Gender + + 168 + + 121.71 + + 305.07 +
      + Sunday Paper + + Jam + + All Gender + + 24 + + 22.35 + + 54.83 +
      + Sunday Paper + + Jelly + + All Gender + + 27 + + 18.20 + + 47.12 +
      + Sunday Paper + + Peanut Butter + + All Gender + + 51 + + 37.67 + + 96.67 +
      + Sunday Paper + + BBB Best + + All Gender + + 10 + + 6.08 + + 16.22 +
      + Sunday Paper + + CDR + + All Gender + + 10 + + 10.47 + + 26.50 +
      + Sunday Paper + + Landslide + + All Gender + + 15 + + 6.20 + + 16.31 +
      + Sunday Paper + + Plato + + All Gender + + 16 + + 14.93 + + 37.64 +
      + Sunday Paper + + Super + + All Gender + +   + +   + +   +
      + Sunday Paper + + Preserves + + All Gender + + 66 + + 43.49 + + 106.45 +
      + Sunday Paper + + Breakfast Foods + + All Gender + + 55 + + 49.80 + + 120.23 +
      + Sunday Paper + + Canned Foods + + All Gender + + 283 + + 249.46 + + 605.11 +
      + Sunday Paper + + Canned Products + + All Gender + + 34 + + 29.65 + + 72.18 +
      + Sunday Paper + + Dairy + + All Gender + + 200 + + 201.94 + + 497.91 +
      + Sunday Paper + + Deli + + All Gender + + 228 + + 188.37 + + 467.53 +
      + Sunday Paper + + Eggs + + All Gender + + 54 + + 47.68 + + 118.44 +
      + Sunday Paper + + Frozen Foods + + All Gender + + 425 + + 330.81 + + 839.15 +
      + Sunday Paper + + Meat + + All Gender + + 18 + + 19.85 + + 52.20 +
      + Sunday Paper + + Produce + + All Gender + + 603 + + 520.95 + + 1,274.70 +
      + Sunday Paper + + Seafood + + All Gender + + 27 + + 26.82 + + 69.49 +
      + Sunday Paper + + Snack Foods + + All Gender + + 469 + + 413.18 + + 1,027.98 +
      + Sunday Paper + + Snacks + + All Gender + + 123 + + 108.50 + + 261.38 +
      + Sunday Paper + + Starchy Foods + + All Gender + + 109 + + 108.91 + + 266.75 +
      + Sunday Paper + + Non-Consumable + + All Gender + + 803 + + 681.86 + + 1,676.70 +
      + Sunday Paper + + Carousel + + All Gender + + 7 + + 6.70 + + 14.68 +
      + Sunday Paper + + Checkout + + All Gender + + 17 + + 13.09 + + 30.89 +
      + Sunday Paper + + Health and Hygiene + + All Gender + + 278 + + 227.06 + + 565.99 +
      + Sunday Paper + + Household + + All Gender + + 420 + + 371.58 + + 911.69 +
      + Sunday Paper + + Periodicals + + All Gender + + 81 + + 63.43 + + 153.45 +
      + Sunday Paper, Radio + + All Products + + All Gender + + 5,945 + + 5,027.31 + + 12,551.96 +
      + Sunday Paper, Radio + + Drink + + All Gender + + 591 + + 454.03 + + 1,129.94 +
      + Sunday Paper, Radio + + Food + + All Gender + + 4,239 + + 3,612.38 + + 9,033.23 +
      + Sunday Paper, Radio + + Baked Goods + + All Gender + + 152 + + 109.11 + + 274.39 +
      + Sunday Paper, Radio + + Baking Goods + + All Gender + + 482 + + 367.13 + + 913.84 +
      + Sunday Paper, Radio + + Baking Goods + + All Gender + + 206 + + 152.72 + + 381.59 +
      + Sunday Paper, Radio + + Jams and Jellies + + All Gender + + 276 + + 214.41 + + 532.25 +
      + Sunday Paper, Radio + + Jam + + All Gender + + 52 + + 52.39 + + 126.62 +
      + Sunday Paper, Radio + + Jelly + + All Gender + + 74 + + 53.93 + + 135.03 +
      + Sunday Paper, Radio + + Peanut Butter + + All Gender + + 64 + + 50.10 + + 126.71 +
      + Sunday Paper, Radio + + BBB Best + + All Gender + + 14 + + 11.58 + + 27.40 +
      + Sunday Paper, Radio + + CDR + + All Gender + + 17 + + 14.68 + + 41.25 +
      + Sunday Paper, Radio + + Landslide + + All Gender + + 14 + + 6.62 + + 17.04 +
      + Sunday Paper, Radio + + Plato + + All Gender + + 7 + + 6.91 + + 17.15 +
      + Sunday Paper, Radio + + Super + + All Gender + + 12 + + 10.31 + + 23.87 +
      + Sunday Paper, Radio + + Preserves + + All Gender + + 86 + + 57.99 + + 143.89 +
      + Sunday Paper, Radio + + Breakfast Foods + + All Gender + + 80 + + 62.80 + + 154.04 +
      + Sunday Paper, Radio + + Canned Foods + + All Gender + + 456 + + 361.79 + + 914.81 +
      + Sunday Paper, Radio + + Canned Products + + All Gender + + 45 + + 39.72 + + 95.88 +
      + Sunday Paper, Radio + + Dairy + + All Gender + + 283 + + 296.91 + + 722.75 +
      + Sunday Paper, Radio + + Deli + + All Gender + + 252 + + 190.32 + + 479.59 +
      + Sunday Paper, Radio + + Eggs + + All Gender + + 114 + + 104.65 + + 256.15 +
      + Sunday Paper, Radio + + Frozen Foods + + All Gender + + 599 + + 490.33 + + 1,222.54 +
      + Sunday Paper, Radio + + Meat + + All Gender + + 40 + + 31.66 + + 84.76 +
      + Sunday Paper, Radio + + Produce + + All Gender + + 858 + + 752.62 + + 1,886.01 +
      + Sunday Paper, Radio + + Seafood + + All Gender + + 27 + + 20.66 + + 50.39 +
      + Sunday Paper, Radio + + Snack Foods + + All Gender + + 596 + + 555.70 + + 1,402.21 +
      + Sunday Paper, Radio + + Snacks + + All Gender + + 147 + + 120.43 + + 304.18 +
      + Sunday Paper, Radio + + Starchy Foods + + All Gender + + 108 + + 108.55 + + 271.69 +
      + Sunday Paper, Radio + + Non-Consumable + + All Gender + + 1,115 + + 960.90 + + 2,388.79 +
      + Sunday Paper, Radio + + Carousel + + All Gender + + 18 + + 10.99 + + 26.94 +
      + Sunday Paper, Radio + + Checkout + + All Gender + + 26 + + 24.68 + + 62.14 +
      + Sunday Paper, Radio + + Health and Hygiene + + All Gender + + 378 + + 309.37 + + 771.48 +
      + Sunday Paper, Radio + + Household + + All Gender + + 585 + + 516.99 + + 1,276.16 +
      + Sunday Paper, Radio + + Periodicals + + All Gender + + 108 + + 98.86 + + 252.07 +
      + Sunday Paper, Radio, TV + + All Products + + All Gender + + 2,726 + + 2,341.58 + + 5,819.33 +
      + Sunday Paper, Radio, TV + + Drink + + All Gender + + 225 + + 163.09 + + 403.51 +
      + Sunday Paper, Radio, TV + + Food + + All Gender + + 2,021 + + 1,762.18 + + 4,377.85 +
      + Sunday Paper, Radio, TV + + Baked Goods + + All Gender + + 67 + + 66.17 + + 163.29 +
      + Sunday Paper, Radio, TV + + Baking Goods + + All Gender + + 228 + + 182.98 + + 455.90 +
      + Sunday Paper, Radio, TV + + Baking Goods + + All Gender + + 90 + + 73.09 + + 176.63 +
      + Sunday Paper, Radio, TV + + Jams and Jellies + + All Gender + + 138 + + 109.90 + + 279.27 +
      + Sunday Paper, Radio, TV + + Jam + + All Gender + + 37 + + 31.30 + + 78.56 +
      + Sunday Paper, Radio, TV + + Jelly + + All Gender + + 27 + + 16.18 + + 39.92 +
      + Sunday Paper, Radio, TV + + Peanut Butter + + All Gender + + 30 + + 24.01 + + 64.19 +
      + Sunday Paper, Radio, TV + + BBB Best + + All Gender + + 11 + + 9.78 + + 23.86 +
      + Sunday Paper, Radio, TV + + CDR + + All Gender + +   + +   + +   +
      + Sunday Paper, Radio, TV + + Landslide + + All Gender + + 4 + + 2.39 + + 5.68 +
      + Sunday Paper, Radio, TV + + Plato + + All Gender + + 5 + + 3.85 + + 11.60 +
      + Sunday Paper, Radio, TV + + Super + + All Gender + + 10 + + 7.99 + + 23.05 +
      + Sunday Paper, Radio, TV + + Preserves + + All Gender + + 44 + + 38.41 + + 96.60 +
      + Sunday Paper, Radio, TV + + Breakfast Foods + + All Gender + + 38 + + 32.76 + + 89.85 +
      + Sunday Paper, Radio, TV + + Canned Foods + + All Gender + + 180 + + 138.77 + + 340.04 +
      + Sunday Paper, Radio, TV + + Canned Products + + All Gender + + 14 + + 12.00 + + 28.28 +
      + Sunday Paper, Radio, TV + + Dairy + + All Gender + + 121 + + 125.32 + + 305.43 +
      + Sunday Paper, Radio, TV + + Deli + + All Gender + + 131 + + 98.93 + + 245.42 +
      + Sunday Paper, Radio, TV + + Eggs + + All Gender + + 39 + + 39.57 + + 91.99 +
      + Sunday Paper, Radio, TV + + Frozen Foods + + All Gender + + 279 + + 207.59 + + 514.95 +
      + Sunday Paper, Radio, TV + + Meat + + All Gender + + 12 + + 11.77 + + 30.23 +
      + Sunday Paper, Radio, TV + + Produce + + All Gender + + 411 + + 382.14 + + 943.93 +
      + Sunday Paper, Radio, TV + + Seafood + + All Gender + + 31 + + 28.07 + + 69.82 +
      + Sunday Paper, Radio, TV + + Snack Foods + + All Gender + + 346 + + 318.26 + + 798.50 +
      + Sunday Paper, Radio, TV + + Snacks + + All Gender + + 75 + + 65.49 + + 174.02 +
      + Sunday Paper, Radio, TV + + Starchy Foods + + All Gender + + 49 + + 52.37 + + 126.20 +
      + Sunday Paper, Radio, TV + + Non-Consumable + + All Gender + + 480 + + 416.30 + + 1,037.97 +
      + Sunday Paper, Radio, TV + + Carousel + + All Gender + + 21 + + 11.63 + + 27.92 +
      + Sunday Paper, Radio, TV + + Checkout + + All Gender + + 10 + + 8.12 + + 19.80 +
      + Sunday Paper, Radio, TV + + Health and Hygiene + + All Gender + + 138 + + 110.35 + + 276.31 +
      + Sunday Paper, Radio, TV + + Household + + All Gender + + 262 + + 244.90 + + 608.52 +
      + Sunday Paper, Radio, TV + + Periodicals + + All Gender + + 49 + + 41.30 + + 105.42 +
      + TV + + All Products + + All Gender + + 3,607 + + 3,116.40 + + 7,786.21 +
      + TV + + Drink + + All Gender + + 332 + + 283.18 + + 721.07 +
      + TV + + Food + + All Gender + + 2,563 + + 2,238.13 + + 5,573.27 +
      + TV + + Baked Goods + + All Gender + + 114 + + 103.40 + + 262.97 +
      + TV + + Baking Goods + + All Gender + + 237 + + 185.55 + + 464.23 +
      + TV + + Baking Goods + + All Gender + + 95 + + 74.29 + + 190.59 +
      + TV + + Jams and Jellies + + All Gender + + 142 + + 111.25 + + 273.64 +
      + TV + + Jam + + All Gender + + 38 + + 32.28 + + 77.58 +
      + TV + + Jelly + + All Gender + + 35 + + 24.64 + + 63.38 +
      + TV + + Peanut Butter + + All Gender + + 31 + + 21.83 + + 56.80 +
      + TV + + BBB Best + + All Gender + +   + +   + +   +
      + TV + + CDR + + All Gender + + 11 + + 9.78 + + 27.19 +
      + TV + + Landslide + + All Gender + + 7 + + 2.61 + + 7.12 +
      + TV + + Plato + + All Gender + + 6 + + 4.95 + + 12.13 +
      + TV + + Super + + All Gender + + 7 + + 4.48 + + 10.36 +
      + TV + + Preserves + + All Gender + + 38 + + 32.51 + + 75.88 +
      + TV + + Breakfast Foods + + All Gender + + 36 + + 30.11 + + 79.89 +
      + TV + + Canned Foods + + All Gender + + 240 + + 200.00 + + 519.91 +
      + TV + + Canned Products + + All Gender + + 26 + + 15.00 + + 38.65 +
      + TV + + Dairy + + All Gender + + 179 + + 183.73 + + 458.87 +
      + TV + + Deli + + All Gender + + 155 + + 139.76 + + 342.51 +
      + TV + + Eggs + + All Gender + + 42 + + 32.74 + + 80.93 +
      + TV + + Frozen Foods + + All Gender + + 352 + + 300.42 + + 738.40 +
      + TV + + Meat + + All Gender + + 22 + + 19.76 + + 49.27 +
      + TV + + Produce + + All Gender + + 543 + + 456.53 + + 1,145.45 +
      + TV + + Seafood + + All Gender + + 34 + + 30.71 + + 75.47 +
      + TV + + Snack Foods + + All Gender + + 401 + + 377.01 + + 927.50 +
      + TV + + Snacks + + All Gender + + 99 + + 92.80 + + 220.54 +
      + TV + + Starchy Foods + + All Gender + + 83 + + 70.61 + + 168.68 +
      + TV + + Non-Consumable + + All Gender + + 712 + + 595.08 + + 1,491.87 +
      + TV + + Carousel + + All Gender + + 4 + + 3.13 + + 9.20 +
      + TV + + Checkout + + All Gender + + 34 + + 34.12 + + 86.21 +
      + TV + + Health and Hygiene + + All Gender + + 249 + + 196.08 + + 486.46 +
      + TV + + Household + + All Gender + + 361 + + 316.09 + + 795.40 +
      + TV + + Periodicals + + All Gender + + 64 + + 45.67 + + 114.60 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/insane-rows-true-true-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/insane-rows-true-true-true-result.html index 41f5da8d..b4072939 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/insane-rows-true-true-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/insane-rows-true-true-true-result.html @@ -1,12229 +1,12229 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      - Promotion Media - - Product - - Gender - - Measures - - Measures - - Measures -
      - (All) - - Media Type - - (All) - - Product Family - - Product Department - - Product Category - - Product Subcategory - - Brand Name - - Product Name - - (All) - - Gender - - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - All Products - - All Gender - - 266,773 - - 225,627.23 - - 565,238.13 -
      - All Media - - All Products - - Drink - - All Gender - - 24,597 - - 19,477.23 - - 48,836.21 -
      - All Media - - All Products - - Food - - All Gender - - 191,940 - - 163,270.72 - - 409,035.59 -
      - All Media - - All Products - - Food - - Baked Goods - - All Gender - - 7,870 - - 6,564.09 - - 16,455.43 -
      - All Media - - All Products - - Food - - Baking Goods - - All Gender - - 20,245 - - 15,370.61 - - 38,670.41 -
      - All Media - - All Products - - Food - - Baking Goods - - Baking Goods - - All Gender - - 8,357 - - 6,123.32 - - 15,446.69 -
      - All Media - - All Products - - Food - - Baking Goods - - Baking Goods - - All Gender - - F - - 4,005 - - 2,907.70 - - 7,313.61 -
      - All Media - - All Products - - Food - - Baking Goods - - Baking Goods - - All Gender - - M - - 4,352 - - 3,215.62 - - 8,133.08 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - All Gender - - 11,888 - - 9,247.29 - - 23,223.72 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jam - - All Gender - - 2,556 - - 2,132.27 - - 5,401.81 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jelly - - All Gender - - 2,565 - - 1,830.04 - - 4,609.61 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jelly - - All Gender - - F - - 1,309 - - 956.94 - - 2,414.94 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jelly - - All Gender - - M - - 1,256 - - 873.10 - - 2,194.67 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - All Gender - - 2,667 - - 2,097.37 - - 5,231.08 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - All Gender - - 556 - - 424.38 - - 1,055.72 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - All Gender - - F - - 271 - - 201.08 - - 500.39 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - All Gender - - M - - 285 - - 223.30 - - 555.33 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - BBB Best Chunky Peanut Butter - - All Gender - - 188 - - 147.32 - - 370.36 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - BBB Best Chunky Peanut Butter - - All Gender - - F - - 107 - - 85.81 - - 210.79 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - BBB Best Chunky Peanut Butter - - All Gender - - M - - 81 - - 61.50 - - 159.57 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - BBB Best Creamy Peanut Butter - - All Gender - - 201 - - 87.86 - - 221.10 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - BBB Best Creamy Peanut Butter - - All Gender - - F - - 99 - - 43.35 - - 108.90 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - BBB Best Creamy Peanut Butter - - All Gender - - M - - 102 - - 44.51 - - 112.20 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - BBB Best Extra Chunky Peanut Butter - - All Gender - - 167 - - 189.21 - - 464.26 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - BBB Best Extra Chunky Peanut Butter - - All Gender - - F - - 65 - - 71.92 - - 180.70 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - BBB Best Extra Chunky Peanut Butter - - All Gender - - M - - 102 - - 117.29 - - 283.56 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - CDR - - All Gender - - 545 - - 538.88 - - 1,326.30 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Landslide - - All Gender - - 531 - - 256.16 - - 635.29 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Plato - - All Gender - - 520 - - 447.73 - - 1,132.16 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Super - - All Gender - - 515 - - 430.21 - - 1,081.61 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Preserves - - All Gender - - 4,100 - - 3,187.61 - - 7,981.22 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Preserves - - All Gender - - F - - 1,946 - - 1,472.42 - - 3,717.80 -
      - All Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Preserves - - All Gender - - M - - 2,154 - - 1,715.19 - - 4,263.42 -
      - All Media - - All Products - - Food - - Breakfast Foods - - All Gender - - 3,317 - - 2,756.80 - - 6,941.46 -
      - All Media - - All Products - - Food - - Canned Foods - - All Gender - - 19,026 - - 15,894.53 - - 39,774.34 -
      - All Media - - All Products - - Food - - Canned Foods - - Canned Anchovies - - All Gender - - 900 - - 913.88 - - 2,296.38 -
      - All Media - - All Products - - Food - - Canned Foods - - Canned Clams - - All Gender - - 882 - - 759.80 - - 1,912.68 -
      - All Media - - All Products - - Food - - Canned Foods - - Canned Clams - - Clams - - All Gender - - 882 - - 759.80 - - 1,912.68 -
      - All Media - - All Products - - Food - - Canned Foods - - Canned Clams - - Clams - - Better - - All Gender - - 189 - - 151.14 - - 398.79 -
      - All Media - - All Products - - Food - - Canned Foods - - Canned Clams - - Clams - - Blue Label - - All Gender - - 165 - - 112.82 - - 278.85 -
      - All Media - - All Products - - Food - - Canned Foods - - Canned Clams - - Clams - - Bravo - - All Gender - - 184 - - 280.70 - - 708.40 -
      - All Media - - All Products - - Food - - Canned Foods - - Canned Clams - - Clams - - Just Right - - All Gender - - 177 - - 161.96 - - 394.71 -
      - All Media - - All Products - - Food - - Canned Foods - - Canned Clams - - Clams - - Pleasant - - All Gender - - 167 - - 53.17 - - 131.93 -
      - All Media - - All Products - - Food - - Canned Foods - - Canned Oysters - - All Gender - - 708 - - 571.50 - - 1,442.77 -
      - All Media - - All Products - - Food - - Canned Foods - - Canned Sardines - - All Gender - - 819 - - 537.59 - - 1,357.80 -
      - All Media - - All Products - - Food - - Canned Foods - - Canned Shrimp - - All Gender - - 804 - - 858.39 - - 2,146.49 -
      - All Media - - All Products - - Food - - Canned Foods - - Canned Soup - - All Gender - - 8,006 - - 6,408.29 - - 15,966.10 -
      - All Media - - All Products - - Food - - Canned Foods - - Canned Tuna - - All Gender - - 1,710 - - 1,288.52 - - 3,210.76 -
      - All Media - - All Products - - Food - - Canned Foods - - Vegetables - - All Gender - - 5,197 - - 4,556.57 - - 11,441.36 -
      - All Media - - All Products - - Food - - Canned Products - - All Gender - - 1,812 - - 1,317.13 - - 3,314.52 -
      - All Media - - All Products - - Food - - Dairy - - All Gender - - 12,885 - - 12,228.85 - - 30,508.85 -
      - All Media - - All Products - - Food - - Deli - - All Gender - - 12,037 - - 10,108.87 - - 25,318.93 -
      - All Media - - All Products - - Food - - Deli - - Meat - - All Gender - - 9,433 - - 8,215.81 - - 20,616.29 -
      - All Media - - All Products - - Food - - Deli - - Meat - - Bologna - - All Gender - - 2,588 - - 2,340.24 - - 5,859.95 -
      - All Media - - All Products - - Food - - Deli - - Meat - - Deli Meats - - All Gender - - 3,339 - - 2,851.18 - - 7,191.24 -
      - All Media - - All Products - - Food - - Deli - - Meat - - Deli Meats - - All Gender - - F - - 1,653 - - 1,414.49 - - 3,579.34 -
      - All Media - - All Products - - Food - - Deli - - Meat - - Deli Meats - - All Gender - - M - - 1,686 - - 1,436.69 - - 3,611.90 -
      - All Media - - All Products - - Food - - Deli - - Meat - - Fresh Chicken - - All Gender - - 878 - - 842.85 - - 2,091.52 -
      - All Media - - All Products - - Food - - Deli - - Meat - - Hot Dogs - - All Gender - - 2,628 - - 2,181.55 - - 5,473.58 -
      - All Media - - All Products - - Food - - Deli - - Side Dishes - - All Gender - - 2,604 - - 1,893.06 - - 4,702.64 -
      - All Media - - All Products - - Food - - Eggs - - All Gender - - 4,132 - - 3,684.90 - - 9,200.76 -
      - All Media - - All Products - - Food - - Frozen Foods - - All Gender - - 26,655 - - 22,030.66 - - 55,207.50 -
      - All Media - - All Products - - Food - - Meat - - All Gender - - 1,714 - - 1,465.42 - - 3,669.89 -
      - All Media - - All Products - - Food - - Produce - - All Gender - - 37,792 - - 32,831.33 - - 82,248.42 -
      - All Media - - All Products - - Food - - Seafood - - All Gender - - 1,764 - - 1,520.70 - - 3,809.14 -
      - All Media - - All Products - - Food - - Snack Foods - - All Gender - - 30,545 - - 26,963.34 - - 67,609.82 -
      - All Media - - All Products - - Food - - Snacks - - All Gender - - 6,884 - - 5,827.58 - - 14,550.05 -
      - All Media - - All Products - - Food - - Starchy Foods - - All Gender - - 5,262 - - 4,705.91 - - 11,756.07 -
      - All Media - - All Products - - Non-Consumable - - All Gender - - 50,236 - - 42,879.28 - - 107,366.33 -
      - All Media - - All Products - - Non-Consumable - - Carousel - - All Gender - - 841 - - 595.97 - - 1,500.11 -
      - All Media - - All Products - - Non-Consumable - - Checkout - - All Gender - - 1,779 - - 1,525.04 - - 3,767.71 -
      - All Media - - All Products - - Non-Consumable - - Health and Hygiene - - All Gender - - 16,284 - - 12,972.99 - - 32,571.86 -
      - All Media - - All Products - - Non-Consumable - - Household - - All Gender - - 27,038 - - 24,170.73 - - 60,469.89 -
      - All Media - - All Products - - Non-Consumable - - Periodicals - - All Gender - - 4,294 - - 3,614.55 - - 9,056.76 -
      - All Media - - Bulk Mail - - All Products - - All Gender - - 4,320 - - 3,740.95 - - 9,349.07 -
      - All Media - - Cash Register Handout - - All Products - - All Gender - - 6,697 - - 5,715.67 - - 14,321.33 -
      - All Media - - Daily Paper - - All Products - - All Gender - - 7,738 - - 6,559.23 - - 16,479.81 -
      - All Media - - Daily Paper, Radio - - All Products - - All Gender - - 6,891 - - 5,668.77 - - 14,169.42 -
      - All Media - - Daily Paper, Radio, TV - - All Products - - All Gender - - 9,513 - - 8,055.22 - - 20,173.97 -
      - All Media - - In-Store Coupon - - All Products - - All Gender - - 3,798 - - 3,263.11 - - 8,162.46 -
      - All Media - - In-Store Coupon - - All Products - - Drink - - All Gender - - 345 - - 282.44 - - 708.38 -
      - All Media - - In-Store Coupon - - All Products - - Food - - All Gender - - 2,737 - - 2,345.57 - - 5,889.34 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Baked Goods - - All Gender - - 131 - - 114.11 - - 279.11 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Baking Goods - - All Gender - - 308 - - 252.88 - - 632.01 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Baking Goods - - Baking Goods - - All Gender - - 146 - - 103.30 - - 261.44 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Baking Goods - - Jams and Jellies - - All Gender - - 162 - - 149.58 - - 370.57 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jam - - All Gender - - 55 - - 58.16 - - 141.19 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jelly - - All Gender - - 32 - - 23.96 - - 62.12 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - All Gender - - 22 - - 19.54 - - 48.72 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - All Gender - - 7 - - 6.72 - - 16.10 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - CDR - - All Gender - - 10 - - 9.81 - - 24.32 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Landslide - - All Gender - -   - -   - -   -
      - All Media - - In-Store Coupon - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Plato - - All Gender - - 3 - - 2.32 - - 6.32 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Super - - All Gender - - 2 - - .69 - - 1.98 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Preserves - - All Gender - - 53 - - 47.92 - - 118.54 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Breakfast Foods - - All Gender - - 59 - - 49.22 - - 125.19 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Breakfast Foods - - All Gender - - F - - 33 - - 22.88 - - 54.84 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Breakfast Foods - - All Gender - - M - - 26 - - 26.34 - - 70.35 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Canned Foods - - All Gender - - 245 - - 200.61 - - 506.67 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Canned Products - - All Gender - - 15 - - 9.58 - - 26.17 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Dairy - - All Gender - - 166 - - 153.42 - - 372.01 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Deli - - All Gender - - 180 - - 163.58 - - 392.68 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Eggs - - All Gender - - 56 - - 42.51 - - 108.90 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Frozen Foods - - All Gender - - 374 - - 301.63 - - 773.52 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Meat - - All Gender - - 31 - - 23.91 - - 70.35 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Produce - - All Gender - - 563 - - 499.63 - - 1,257.05 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Seafood - - All Gender - - 34 - - 30.06 - - 76.09 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Snack Foods - - All Gender - - 439 - - 390.35 - - 989.13 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Snacks - - All Gender - - 78 - - 63.77 - - 153.02 -
      - All Media - - In-Store Coupon - - All Products - - Food - - Starchy Foods - - All Gender - - 58 - - 50.30 - - 127.44 -
      - All Media - - In-Store Coupon - - All Products - - Non-Consumable - - All Gender - - 716 - - 635.10 - - 1,564.74 -
      - All Media - - In-Store Coupon - - All Products - - Non-Consumable - - Carousel - - All Gender - - 17 - - 8.77 - - 24.18 -
      - All Media - - In-Store Coupon - - All Products - - Non-Consumable - - Checkout - - All Gender - - 23 - - 15.20 - - 40.19 -
      - All Media - - In-Store Coupon - - All Products - - Non-Consumable - - Health and Hygiene - - All Gender - - 251 - - 193.53 - - 477.21 -
      - All Media - - In-Store Coupon - - All Products - - Non-Consumable - - Household - - All Gender - - 374 - - 375.66 - - 916.97 -
      - All Media - - In-Store Coupon - - All Products - - Non-Consumable - - Periodicals - - All Gender - - 51 - - 41.94 - - 106.19 -
      - All Media - - No Media - - All Products - - All Gender - - 195,448 - - 165,214.85 - - 414,026.92 -
      - All Media - - No Media - - All Products - - Drink - - All Gender - - 17,896 - - 14,211.41 - - 35,681.85 -
      - All Media - - No Media - - All Products - - Food - - All Gender - - 140,577 - - 119,469.36 - - 299,356.11 -
      - All Media - - No Media - - All Products - - Food - - Baked Goods - - All Gender - - 5,753 - - 4,775.86 - - 11,972.46 -
      - All Media - - No Media - - All Products - - Food - - Baking Goods - - All Gender - - 14,849 - - 11,226.15 - - 28,312.78 -
      - All Media - - No Media - - All Products - - Food - - Baking Goods - - Baking Goods - - All Gender - - 5,979 - - 4,347.34 - - 11,002.73 -
      - All Media - - No Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - All Gender - - 8,870 - - 6,878.81 - - 17,310.05 -
      - All Media - - No Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jam - - All Gender - - 1,883 - - 1,554.13 - - 3,965.74 -
      - All Media - - No Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jelly - - All Gender - - 1,936 - - 1,394.32 - - 3,504.71 -
      - All Media - - No Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - All Gender - - 1,984 - - 1,534.19 - - 3,828.01 -
      - All Media - - No Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - All Gender - - 406 - - 293.97 - - 735.29 -
      - All Media - - No Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - CDR - - All Gender - - 411 - - 401.88 - - 998.12 -
      - All Media - - No Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Landslide - - All Gender - - 401 - - 195.51 - - 478.44 -
      - All Media - - No Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Plato - - All Gender - - 384 - - 331.26 - - 832.92 -
      - All Media - - No Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Super - - All Gender - - 382 - - 311.57 - - 783.24 -
      - All Media - - No Media - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Preserves - - All Gender - - 3,067 - - 2,396.16 - - 6,011.59 -
      - All Media - - No Media - - All Products - - Food - - Breakfast Foods - - All Gender - - 2,418 - - 1,996.45 - - 5,016.10 -
      - All Media - - No Media - - All Products - - Food - - Canned Foods - - All Gender - - 13,861 - - 11,647.47 - - 29,102.79 -
      - All Media - - No Media - - All Products - - Food - - Canned Products - - All Gender - - 1,344 - - 960.82 - - 2,424.98 -
      - All Media - - No Media - - All Products - - Food - - Dairy - - All Gender - - 9,510 - - 8,981.13 - - 22,454.02 -
      - All Media - - No Media - - All Products - - Food - - Deli - - All Gender - - 8,695 - - 7,353.56 - - 18,410.26 -
      - All Media - - No Media - - All Products - - Food - - Eggs - - All Gender - - 2,976 - - 2,640.47 - - 6,606.25 -
      - All Media - - No Media - - All Products - - Food - - Frozen Foods - - All Gender - - 19,450 - - 16,127.24 - - 40,411.08 -
      - All Media - - No Media - - All Products - - Food - - Meat - - All Gender - - 1,236 - - 1,068.07 - - 2,646.00 -
      - All Media - - No Media - - All Products - - Food - - Produce - - All Gender - - 27,637 - - 24,036.36 - - 60,203.58 -
      - All Media - - No Media - - All Products - - Food - - Seafood - - All Gender - - 1,292 - - 1,114.69 - - 2,774.43 -
      - All Media - - No Media - - All Products - - Food - - Snack Foods - - All Gender - - 22,525 - - 19,800.82 - - 49,680.71 -
      - All Media - - No Media - - All Products - - Food - - Snacks - - All Gender - - 5,100 - - 4,264.55 - - 10,690.26 -
      - All Media - - No Media - - All Products - - Food - - Starchy Foods - - All Gender - - 3,931 - - 3,475.74 - - 8,650.41 -
      - All Media - - No Media - - All Products - - Non-Consumable - - All Gender - - 36,975 - - 31,534.08 - - 78,988.96 -
      - All Media - - No Media - - All Products - - Non-Consumable - - Carousel - - All Gender - - 584 - - 419.65 - - 1,050.75 -
      - All Media - - No Media - - All Products - - Non-Consumable - - Checkout - - All Gender - - 1,305 - - 1,113.97 - - 2,768.66 -
      - All Media - - No Media - - All Products - - Non-Consumable - - Health and Hygiene - - All Gender - - 11,845 - - 9,413.25 - - 23,621.12 -
      - All Media - - No Media - - All Products - - Non-Consumable - - Household - - All Gender - - 20,091 - - 17,929.20 - - 44,881.13 -
      - All Media - - No Media - - All Products - - Non-Consumable - - Periodicals - - All Gender - - 3,150 - - 2,658.00 - - 6,667.30 -
      - All Media - - Product Attachment - - All Products - - All Gender - - 7,544 - - 6,306.24 - - 15,898.25 -
      - All Media - - Product Attachment - - All Products - - Drink - - All Gender - - 713 - - 555.05 - - 1,403.65 -
      - All Media - - Product Attachment - - All Products - - Food - - All Gender - - 5,441 - - 4,571.71 - - 11,525.25 -
      - All Media - - Product Attachment - - All Products - - Food - - Baked Goods - - All Gender - - 213 - - 175.69 - - 445.60 -
      - All Media - - Product Attachment - - All Products - - Food - - Baking Goods - - All Gender - - 547 - - 410.31 - - 1,032.59 -
      - All Media - - Product Attachment - - All Products - - Food - - Baking Goods - - Baking Goods - - All Gender - - 258 - - 191.48 - - 470.58 -
      - All Media - - Product Attachment - - All Products - - Food - - Baking Goods - - Jams and Jellies - - All Gender - - 289 - - 218.83 - - 562.01 -
      - All Media - - Product Attachment - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jam - - All Gender - - 66 - - 48.03 - - 128.68 -
      - All Media - - Product Attachment - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jelly - - All Gender - - 45 - - 34.12 - - 90.62 -
      - All Media - - Product Attachment - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - All Gender - - 63 - - 47.71 - - 122.31 -
      - All Media - - Product Attachment - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - All Gender - - 15 - - 14.53 - - 38.46 -
      - All Media - - Product Attachment - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - CDR - - All Gender - - 13 - - 11.94 - - 30.57 -
      - All Media - - Product Attachment - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Landslide - - All Gender - - 12 - - 5.32 - - 14.28 -
      - All Media - - Product Attachment - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Plato - - All Gender - - 9 - - 7.16 - - 17.43 -
      - All Media - - Product Attachment - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Super - - All Gender - - 14 - - 8.75 - - 21.57 -
      - All Media - - Product Attachment - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Preserves - - All Gender - - 115 - - 88.98 - - 220.40 -
      - All Media - - Product Attachment - - All Products - - Food - - Breakfast Foods - - All Gender - - 103 - - 87.35 - - 220.75 -
      - All Media - - Product Attachment - - All Products - - Food - - Canned Foods - - All Gender - - 564 - - 463.28 - - 1,154.91 -
      - All Media - - Product Attachment - - All Products - - Food - - Canned Products - - All Gender - - 60 - - 51.61 - - 124.24 -
      - All Media - - Product Attachment - - All Products - - Food - - Dairy - - All Gender - - 355 - - 339.81 - - 849.78 -
      - All Media - - Product Attachment - - All Products - - Food - - Deli - - All Gender - - 324 - - 243.64 - - 618.23 -
      - All Media - - Product Attachment - - All Products - - Food - - Eggs - - All Gender - - 118 - - 97.43 - - 241.21 -
      - All Media - - Product Attachment - - All Products - - Food - - Frozen Foods - - All Gender - - 812 - - 665.48 - - 1,692.11 -
      - All Media - - Product Attachment - - All Products - - Food - - Meat - - All Gender - - 54 - - 51.36 - - 127.83 -
      - All Media - - Product Attachment - - All Products - - Food - - Produce - - All Gender - - 1,069 - - 909.24 - - 2,287.61 -
      - All Media - - Product Attachment - - All Products - - Food - - Seafood - - All Gender - - 45 - - 36.98 - - 100.61 -
      - All Media - - Product Attachment - - All Products - - Food - - Snack Foods - - All Gender - - 819 - - 726.73 - - 1,847.28 -
      - All Media - - Product Attachment - - All Products - - Food - - Snacks - - All Gender - - 209 - - 186.22 - - 450.03 -
      - All Media - - Product Attachment - - All Products - - Food - - Starchy Foods - - All Gender - - 149 - - 126.59 - - 332.47 -
      - All Media - - Product Attachment - - All Products - - Non-Consumable - - All Gender - - 1,390 - - 1,179.48 - - 2,969.35 -
      - All Media - - Product Attachment - - All Products - - Non-Consumable - - Carousel - - All Gender - - 14 - - 7.99 - - 21.21 -
      - All Media - - Product Attachment - - All Products - - Non-Consumable - - Checkout - - All Gender - - 48 - - 40.45 - - 100.61 -
      - All Media - - Product Attachment - - All Products - - Non-Consumable - - Health and Hygiene - - All Gender - - 440 - - 356.54 - - 901.73 -
      - All Media - - Product Attachment - - All Products - - Non-Consumable - - Household - - All Gender - - 777 - - 690.03 - - 1,737.96 -
      - All Media - - Product Attachment - - All Products - - Non-Consumable - - Periodicals - - All Gender - - 111 - - 84.48 - - 207.84 -
      - All Media - - Radio - - All Products - - All Gender - - 2,454 - - 2,087.51 - - 5,213.61 -
      - All Media - - Radio - - All Products - - Drink - - All Gender - - 226 - - 182.85 - - 443.68 -
      - All Media - - Radio - - All Products - - Food - - All Gender - - 1,733 - - 1,485.25 - - 3,727.36 -
      - All Media - - Radio - - All Products - - Food - - Baked Goods - - All Gender - - 83 - - 76.51 - - 186.20 -
      - All Media - - Radio - - All Products - - Food - - Baking Goods - - All Gender - - 157 - - 109.10 - - 274.90 -
      - All Media - - Radio - - All Products - - Food - - Baking Goods - - Baking Goods - - All Gender - - 63 - - 45.02 - - 110.43 -
      - All Media - - Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - All Gender - - 94 - - 64.08 - - 164.47 -
      - All Media - - Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jam - - All Gender - - 15 - - 10.42 - - 26.94 -
      - All Media - - Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jelly - - All Gender - - 24 - - 14.54 - - 37.49 -
      - All Media - - Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - All Gender - - 19 - - 16.85 - - 41.82 -
      - All Media - - Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - All Gender - - 10 - - 10.58 - - 24.44 -
      - All Media - - Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - CDR - - All Gender - -   - -   - -   -
      - All Media - - Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Landslide - - All Gender - -   - -   - -   -
      - All Media - - Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Plato - - All Gender - - 4 - - 3.77 - - 9.80 -
      - All Media - - Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Super - - All Gender - - 5 - - 2.50 - - 7.58 -
      - All Media - - Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Preserves - - All Gender - - 36 - - 22.28 - - 58.22 -
      - All Media - - Radio - - All Products - - Food - - Breakfast Foods - - All Gender - - 25 - - 18.78 - - 50.22 -
      - All Media - - Radio - - All Products - - Food - - Canned Foods - - All Gender - - 158 - - 124.79 - - 307.55 -
      - All Media - - Radio - - All Products - - Food - - Canned Products - - All Gender - - 22 - - 17.29 - - 43.42 -
      - All Media - - Radio - - All Products - - Food - - Dairy - - All Gender - - 112 - - 92.12 - - 216.79 -
      - All Media - - Radio - - All Products - - Food - - Deli - - All Gender - - 129 - - 119.14 - - 307.25 -
      - All Media - - Radio - - All Products - - Food - - Eggs - - All Gender - - 25 - - 29.97 - - 71.15 -
      - All Media - - Radio - - All Products - - Food - - Frozen Foods - - All Gender - - 253 - - 202.71 - - 507.45 -
      - All Media - - Radio - - All Products - - Food - - Meat - - All Gender - - 12 - - 11.53 - - 32.85 -
      - All Media - - Radio - - All Products - - Food - - Produce - - All Gender - - 336 - - 292.05 - - 738.20 -
      - All Media - - Radio - - All Products - - Food - - Seafood - - All Gender - - 15 - - 13.28 - - 35.58 -
      - All Media - - Radio - - All Products - - Food - - Snack Foods - - All Gender - - 290 - - 270.59 - - 674.73 -
      - All Media - - Radio - - All Products - - Food - - Snacks - - All Gender - - 60 - - 55.67 - - 144.58 -
      - All Media - - Radio - - All Products - - Food - - Starchy Foods - - All Gender - - 56 - - 51.72 - - 136.49 -
      - All Media - - Radio - - All Products - - Non-Consumable - - All Gender - - 495 - - 419.41 - - 1,042.57 -
      - All Media - - Radio - - All Products - - Non-Consumable - - Carousel - - All Gender - - 15 - - 11.15 - - 26.85 -
      - All Media - - Radio - - All Products - - Non-Consumable - - Checkout - - All Gender - - 21 - - 17.00 - - 42.74 -
      - All Media - - Radio - - All Products - - Non-Consumable - - Health and Hygiene - - All Gender - - 145 - - 114.84 - - 289.80 -
      - All Media - - Radio - - All Products - - Non-Consumable - - Household - - All Gender - - 258 - - 233.31 - - 575.07 -
      - All Media - - Radio - - All Products - - Non-Consumable - - Periodicals - - All Gender - - 56 - - 43.12 - - 108.11 -
      - All Media - - Street Handout - - All Products - - All Gender - - 5,753 - - 4,856.54 - - 12,192.90 -
      - All Media - - Street Handout - - All Products - - Drink - - All Gender - - 512 - - 372.68 - - 943.42 -
      - All Media - - Street Handout - - All Products - - Food - - All Gender - - 4,239 - - 3,650.32 - - 9,151.65 -
      - All Media - - Street Handout - - All Products - - Food - - Baked Goods - - All Gender - - 160 - - 120.12 - - 301.62 -
      - All Media - - Street Handout - - All Products - - Food - - Baking Goods - - All Gender - - 498 - - 373.67 - - 923.22 -
      - All Media - - Street Handout - - All Products - - Food - - Baking Goods - - Baking Goods - - All Gender - - 200 - - 144.16 - - 357.82 -
      - All Media - - Street Handout - - All Products - - Food - - Baking Goods - - Jams and Jellies - - All Gender - - 298 - - 229.51 - - 565.40 -
      - All Media - - Street Handout - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jam - - All Gender - - 53 - - 44.30 - - 112.95 -
      - All Media - - Street Handout - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jelly - - All Gender - - 92 - - 63.14 - - 155.59 -
      - All Media - - Street Handout - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - All Gender - - 51 - - 51.06 - - 118.90 -
      - All Media - - Street Handout - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - All Gender - - 11 - - 10.85 - - 25.72 -
      - All Media - - Street Handout - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - CDR - - All Gender - - 8 - - 9.06 - - 19.73 -
      - All Media - - Street Handout - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Landslide - - All Gender - - 11 - - 6.90 - - 15.54 -
      - All Media - - Street Handout - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Plato - - All Gender - - 9 - - 8.47 - - 20.89 -
      - All Media - - Street Handout - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Super - - All Gender - - 12 - - 15.78 - - 37.02 -
      - All Media - - Street Handout - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Preserves - - All Gender - - 102 - - 71.02 - - 177.96 -
      - All Media - - Street Handout - - All Products - - Food - - Breakfast Foods - - All Gender - - 81 - - 74.32 - - 192.90 -
      - All Media - - Street Handout - - All Products - - Food - - Canned Foods - - All Gender - - 459 - - 413.21 - - 1,021.86 -
      - All Media - - Street Handout - - All Products - - Food - - Canned Products - - All Gender - - 30 - - 19.43 - - 45.68 -
      - All Media - - Street Handout - - All Products - - Food - - Dairy - - All Gender - - 301 - - 285.98 - - 718.61 -
      - All Media - - Street Handout - - All Products - - Food - - Deli - - All Gender - - 305 - - 253.54 - - 638.30 -
      - All Media - - Street Handout - - All Products - - Food - - Eggs - - All Gender - - 66 - - 59.15 - - 156.82 -
      - All Media - - Street Handout - - All Products - - Food - - Frozen Foods - - All Gender - - 612 - - 520.12 - - 1,313.71 -
      - All Media - - Street Handout - - All Products - - Food - - Meat - - All Gender - - 37 - - 29.82 - - 78.24 -
      - All Media - - Street Handout - - All Products - - Food - - Produce - - All Gender - - 745 - - 662.39 - - 1,639.94 -
      - All Media - - Street Handout - - All Products - - Food - - Seafood - - All Gender - - 37 - - 30.12 - - 72.77 -
      - All Media - - Street Handout - - All Products - - Food - - Snack Foods - - All Gender - - 675 - - 600.23 - - 1,515.68 -
      - All Media - - Street Handout - - All Products - - Food - - Snacks - - All Gender - - 144 - - 128.79 - - 321.16 -
      - All Media - - Street Handout - - All Products - - Food - - Starchy Foods - - All Gender - - 89 - - 79.43 - - 211.14 -
      - All Media - - Street Handout - - All Products - - Non-Consumable - - All Gender - - 1,002 - - 833.53 - - 2,097.83 -
      - All Media - - Street Handout - - All Products - - Non-Consumable - - Carousel - - All Gender - - 17 - - 13.53 - - 30.98 -
      - All Media - - Street Handout - - All Products - - Non-Consumable - - Checkout - - All Gender - - 45 - - 34.77 - - 85.38 -
      - All Media - - Street Handout - - All Products - - Non-Consumable - - Health and Hygiene - - All Gender - - 402 - - 318.03 - - 802.92 -
      - All Media - - Street Handout - - All Products - - Non-Consumable - - Household - - All Gender - - 501 - - 436.41 - - 1,105.38 -
      - All Media - - Street Handout - - All Products - - Non-Consumable - - Periodicals - - All Gender - - 37 - - 30.80 - - 73.17 -
      - All Media - - Sunday Paper - - All Products - - All Gender - - 4,339 - - 3,673.86 - - 9,092.89 -
      - All Media - - Sunday Paper - - All Products - - Drink - - All Gender - - 430 - - 345.53 - - 856.73 -
      - All Media - - Sunday Paper - - All Products - - Food - - All Gender - - 3,106 - - 2,646.47 - - 6,559.46 -
      - All Media - - Sunday Paper - - All Products - - Food - - Baked Goods - - All Gender - - 140 - - 110.79 - - 282.55 -
      - All Media - - Sunday Paper - - All Products - - Food - - Baking Goods - - All Gender - - 338 - - 239.76 - - 603.86 -
      - All Media - - Sunday Paper - - All Products - - Food - - Baking Goods - - Baking Goods - - All Gender - - 170 - - 118.05 - - 298.79 -
      - All Media - - Sunday Paper - - All Products - - Food - - Baking Goods - - Jams and Jellies - - All Gender - - 168 - - 121.71 - - 305.07 -
      - All Media - - Sunday Paper - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jam - - All Gender - - 24 - - 22.35 - - 54.83 -
      - All Media - - Sunday Paper - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jelly - - All Gender - - 27 - - 18.20 - - 47.12 -
      - All Media - - Sunday Paper - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - All Gender - - 51 - - 37.67 - - 96.67 -
      - All Media - - Sunday Paper - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - All Gender - - 10 - - 6.08 - - 16.22 -
      - All Media - - Sunday Paper - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - CDR - - All Gender - - 10 - - 10.47 - - 26.50 -
      - All Media - - Sunday Paper - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Landslide - - All Gender - - 15 - - 6.20 - - 16.31 -
      - All Media - - Sunday Paper - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Plato - - All Gender - - 16 - - 14.93 - - 37.64 -
      - All Media - - Sunday Paper - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Super - - All Gender - -   - -   - -   -
      - All Media - - Sunday Paper - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Preserves - - All Gender - - 66 - - 43.49 - - 106.45 -
      - All Media - - Sunday Paper - - All Products - - Food - - Breakfast Foods - - All Gender - - 55 - - 49.80 - - 120.23 -
      - All Media - - Sunday Paper - - All Products - - Food - - Canned Foods - - All Gender - - 283 - - 249.46 - - 605.11 -
      - All Media - - Sunday Paper - - All Products - - Food - - Canned Products - - All Gender - - 34 - - 29.65 - - 72.18 -
      - All Media - - Sunday Paper - - All Products - - Food - - Dairy - - All Gender - - 200 - - 201.94 - - 497.91 -
      - All Media - - Sunday Paper - - All Products - - Food - - Deli - - All Gender - - 228 - - 188.37 - - 467.53 -
      - All Media - - Sunday Paper - - All Products - - Food - - Eggs - - All Gender - - 54 - - 47.68 - - 118.44 -
      - All Media - - Sunday Paper - - All Products - - Food - - Frozen Foods - - All Gender - - 425 - - 330.81 - - 839.15 -
      - All Media - - Sunday Paper - - All Products - - Food - - Meat - - All Gender - - 18 - - 19.85 - - 52.20 -
      - All Media - - Sunday Paper - - All Products - - Food - - Produce - - All Gender - - 603 - - 520.95 - - 1,274.70 -
      - All Media - - Sunday Paper - - All Products - - Food - - Seafood - - All Gender - - 27 - - 26.82 - - 69.49 -
      - All Media - - Sunday Paper - - All Products - - Food - - Snack Foods - - All Gender - - 469 - - 413.18 - - 1,027.98 -
      - All Media - - Sunday Paper - - All Products - - Food - - Snacks - - All Gender - - 123 - - 108.50 - - 261.38 -
      - All Media - - Sunday Paper - - All Products - - Food - - Starchy Foods - - All Gender - - 109 - - 108.91 - - 266.75 -
      - All Media - - Sunday Paper - - All Products - - Non-Consumable - - All Gender - - 803 - - 681.86 - - 1,676.70 -
      - All Media - - Sunday Paper - - All Products - - Non-Consumable - - Carousel - - All Gender - - 7 - - 6.70 - - 14.68 -
      - All Media - - Sunday Paper - - All Products - - Non-Consumable - - Checkout - - All Gender - - 17 - - 13.09 - - 30.89 -
      - All Media - - Sunday Paper - - All Products - - Non-Consumable - - Health and Hygiene - - All Gender - - 278 - - 227.06 - - 565.99 -
      - All Media - - Sunday Paper - - All Products - - Non-Consumable - - Household - - All Gender - - 420 - - 371.58 - - 911.69 -
      - All Media - - Sunday Paper - - All Products - - Non-Consumable - - Periodicals - - All Gender - - 81 - - 63.43 - - 153.45 -
      - All Media - - Sunday Paper, Radio - - All Products - - All Gender - - 5,945 - - 5,027.31 - - 12,551.96 -
      - All Media - - Sunday Paper, Radio - - All Products - - Drink - - All Gender - - 591 - - 454.03 - - 1,129.94 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - All Gender - - 4,239 - - 3,612.38 - - 9,033.23 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Baked Goods - - All Gender - - 152 - - 109.11 - - 274.39 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Baking Goods - - All Gender - - 482 - - 367.13 - - 913.84 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Baking Goods - - Baking Goods - - All Gender - - 206 - - 152.72 - - 381.59 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - All Gender - - 276 - - 214.41 - - 532.25 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jam - - All Gender - - 52 - - 52.39 - - 126.62 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jelly - - All Gender - - 74 - - 53.93 - - 135.03 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - All Gender - - 64 - - 50.10 - - 126.71 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - All Gender - - 14 - - 11.58 - - 27.40 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - CDR - - All Gender - - 17 - - 14.68 - - 41.25 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Landslide - - All Gender - - 14 - - 6.62 - - 17.04 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Plato - - All Gender - - 7 - - 6.91 - - 17.15 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Super - - All Gender - - 12 - - 10.31 - - 23.87 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Preserves - - All Gender - - 86 - - 57.99 - - 143.89 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Breakfast Foods - - All Gender - - 80 - - 62.80 - - 154.04 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Canned Foods - - All Gender - - 456 - - 361.79 - - 914.81 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Canned Products - - All Gender - - 45 - - 39.72 - - 95.88 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Dairy - - All Gender - - 283 - - 296.91 - - 722.75 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Deli - - All Gender - - 252 - - 190.32 - - 479.59 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Eggs - - All Gender - - 114 - - 104.65 - - 256.15 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Frozen Foods - - All Gender - - 599 - - 490.33 - - 1,222.54 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Meat - - All Gender - - 40 - - 31.66 - - 84.76 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Produce - - All Gender - - 858 - - 752.62 - - 1,886.01 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Seafood - - All Gender - - 27 - - 20.66 - - 50.39 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Snack Foods - - All Gender - - 596 - - 555.70 - - 1,402.21 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Snacks - - All Gender - - 147 - - 120.43 - - 304.18 -
      - All Media - - Sunday Paper, Radio - - All Products - - Food - - Starchy Foods - - All Gender - - 108 - - 108.55 - - 271.69 -
      - All Media - - Sunday Paper, Radio - - All Products - - Non-Consumable - - All Gender - - 1,115 - - 960.90 - - 2,388.79 -
      - All Media - - Sunday Paper, Radio - - All Products - - Non-Consumable - - Carousel - - All Gender - - 18 - - 10.99 - - 26.94 -
      - All Media - - Sunday Paper, Radio - - All Products - - Non-Consumable - - Checkout - - All Gender - - 26 - - 24.68 - - 62.14 -
      - All Media - - Sunday Paper, Radio - - All Products - - Non-Consumable - - Health and Hygiene - - All Gender - - 378 - - 309.37 - - 771.48 -
      - All Media - - Sunday Paper, Radio - - All Products - - Non-Consumable - - Household - - All Gender - - 585 - - 516.99 - - 1,276.16 -
      - All Media - - Sunday Paper, Radio - - All Products - - Non-Consumable - - Periodicals - - All Gender - - 108 - - 98.86 - - 252.07 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - All Gender - - 2,726 - - 2,341.58 - - 5,819.33 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Drink - - All Gender - - 225 - - 163.09 - - 403.51 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - All Gender - - 2,021 - - 1,762.18 - - 4,377.85 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Baked Goods - - All Gender - - 67 - - 66.17 - - 163.29 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Baking Goods - - All Gender - - 228 - - 182.98 - - 455.90 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Baking Goods - - Baking Goods - - All Gender - - 90 - - 73.09 - - 176.63 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - All Gender - - 138 - - 109.90 - - 279.27 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jam - - All Gender - - 37 - - 31.30 - - 78.56 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jelly - - All Gender - - 27 - - 16.18 - - 39.92 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - All Gender - - 30 - - 24.01 - - 64.19 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - All Gender - - 11 - - 9.78 - - 23.86 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - CDR - - All Gender - -   - -   - -   -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Landslide - - All Gender - - 4 - - 2.39 - - 5.68 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Plato - - All Gender - - 5 - - 3.85 - - 11.60 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Super - - All Gender - - 10 - - 7.99 - - 23.05 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Preserves - - All Gender - - 44 - - 38.41 - - 96.60 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Breakfast Foods - - All Gender - - 38 - - 32.76 - - 89.85 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Canned Foods - - All Gender - - 180 - - 138.77 - - 340.04 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Canned Products - - All Gender - - 14 - - 12.00 - - 28.28 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Dairy - - All Gender - - 121 - - 125.32 - - 305.43 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Deli - - All Gender - - 131 - - 98.93 - - 245.42 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Eggs - - All Gender - - 39 - - 39.57 - - 91.99 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Frozen Foods - - All Gender - - 279 - - 207.59 - - 514.95 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Meat - - All Gender - - 12 - - 11.77 - - 30.23 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Produce - - All Gender - - 411 - - 382.14 - - 943.93 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Seafood - - All Gender - - 31 - - 28.07 - - 69.82 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Snack Foods - - All Gender - - 346 - - 318.26 - - 798.50 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Snacks - - All Gender - - 75 - - 65.49 - - 174.02 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Food - - Starchy Foods - - All Gender - - 49 - - 52.37 - - 126.20 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Non-Consumable - - All Gender - - 480 - - 416.30 - - 1,037.97 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Non-Consumable - - Carousel - - All Gender - - 21 - - 11.63 - - 27.92 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Non-Consumable - - Checkout - - All Gender - - 10 - - 8.12 - - 19.80 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Non-Consumable - - Health and Hygiene - - All Gender - - 138 - - 110.35 - - 276.31 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Non-Consumable - - Household - - All Gender - - 262 - - 244.90 - - 608.52 -
      - All Media - - Sunday Paper, Radio, TV - - All Products - - Non-Consumable - - Periodicals - - All Gender - - 49 - - 41.30 - - 105.42 -
      - All Media - - TV - - All Products - - All Gender - - 3,607 - - 3,116.40 - - 7,786.21 -
      - All Media - - TV - - All Products - - Drink - - All Gender - - 332 - - 283.18 - - 721.07 -
      - All Media - - TV - - All Products - - Food - - All Gender - - 2,563 - - 2,238.13 - - 5,573.27 -
      - All Media - - TV - - All Products - - Food - - Baked Goods - - All Gender - - 114 - - 103.40 - - 262.97 -
      - All Media - - TV - - All Products - - Food - - Baking Goods - - All Gender - - 237 - - 185.55 - - 464.23 -
      - All Media - - TV - - All Products - - Food - - Baking Goods - - Baking Goods - - All Gender - - 95 - - 74.29 - - 190.59 -
      - All Media - - TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - All Gender - - 142 - - 111.25 - - 273.64 -
      - All Media - - TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jam - - All Gender - - 38 - - 32.28 - - 77.58 -
      - All Media - - TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Jelly - - All Gender - - 35 - - 24.64 - - 63.38 -
      - All Media - - TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - All Gender - - 31 - - 21.83 - - 56.80 -
      - All Media - - TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - BBB Best - - All Gender - -   - -   - -   -
      - All Media - - TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - CDR - - All Gender - - 11 - - 9.78 - - 27.19 -
      - All Media - - TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Landslide - - All Gender - - 7 - - 2.61 - - 7.12 -
      - All Media - - TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Plato - - All Gender - - 6 - - 4.95 - - 12.13 -
      - All Media - - TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Peanut Butter - - Super - - All Gender - - 7 - - 4.48 - - 10.36 -
      - All Media - - TV - - All Products - - Food - - Baking Goods - - Jams and Jellies - - Preserves - - All Gender - - 38 - - 32.51 - - 75.88 -
      - All Media - - TV - - All Products - - Food - - Breakfast Foods - - All Gender - - 36 - - 30.11 - - 79.89 -
      - All Media - - TV - - All Products - - Food - - Canned Foods - - All Gender - - 240 - - 200.00 - - 519.91 -
      - All Media - - TV - - All Products - - Food - - Canned Products - - All Gender - - 26 - - 15.00 - - 38.65 -
      - All Media - - TV - - All Products - - Food - - Dairy - - All Gender - - 179 - - 183.73 - - 458.87 -
      - All Media - - TV - - All Products - - Food - - Deli - - All Gender - - 155 - - 139.76 - - 342.51 -
      - All Media - - TV - - All Products - - Food - - Eggs - - All Gender - - 42 - - 32.74 - - 80.93 -
      - All Media - - TV - - All Products - - Food - - Frozen Foods - - All Gender - - 352 - - 300.42 - - 738.40 -
      - All Media - - TV - - All Products - - Food - - Meat - - All Gender - - 22 - - 19.76 - - 49.27 -
      - All Media - - TV - - All Products - - Food - - Produce - - All Gender - - 543 - - 456.53 - - 1,145.45 -
      - All Media - - TV - - All Products - - Food - - Seafood - - All Gender - - 34 - - 30.71 - - 75.47 -
      - All Media - - TV - - All Products - - Food - - Snack Foods - - All Gender - - 401 - - 377.01 - - 927.50 -
      - All Media - - TV - - All Products - - Food - - Snacks - - All Gender - - 99 - - 92.80 - - 220.54 -
      - All Media - - TV - - All Products - - Food - - Starchy Foods - - All Gender - - 83 - - 70.61 - - 168.68 -
      - All Media - - TV - - All Products - - Non-Consumable - - All Gender - - 712 - - 595.08 - - 1,491.87 -
      - All Media - - TV - - All Products - - Non-Consumable - - Carousel - - All Gender - - 4 - - 3.13 - - 9.20 -
      - All Media - - TV - - All Products - - Non-Consumable - - Checkout - - All Gender - - 34 - - 34.12 - - 86.21 -
      - All Media - - TV - - All Products - - Non-Consumable - - Health and Hygiene - - All Gender - - 249 - - 196.08 - - 486.46 -
      - All Media - - TV - - All Products - - Non-Consumable - - Household - - All Gender - - 361 - - 316.09 - - 795.40 -
      - All Media - - TV - - All Products - - Non-Consumable - - Periodicals - - All Gender - - 64 - - 45.67 - - 114.60 -
      + Promotion Media + + Product + + Gender + + Measures + + Measures + + Measures +
      + (All) + + Media Type + + (All) + + Product Family + + Product Department + + Product Category + + Product Subcategory + + Brand Name + + Product Name + + (All) + + Gender + + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + All Products + + All Gender + + 266,773 + + 225,627.23 + + 565,238.13 +
      + All Media + + All Products + + Drink + + All Gender + + 24,597 + + 19,477.23 + + 48,836.21 +
      + All Media + + All Products + + Food + + All Gender + + 191,940 + + 163,270.72 + + 409,035.59 +
      + All Media + + All Products + + Food + + Baked Goods + + All Gender + + 7,870 + + 6,564.09 + + 16,455.43 +
      + All Media + + All Products + + Food + + Baking Goods + + All Gender + + 20,245 + + 15,370.61 + + 38,670.41 +
      + All Media + + All Products + + Food + + Baking Goods + + Baking Goods + + All Gender + + 8,357 + + 6,123.32 + + 15,446.69 +
      + All Media + + All Products + + Food + + Baking Goods + + Baking Goods + + All Gender + + F + + 4,005 + + 2,907.70 + + 7,313.61 +
      + All Media + + All Products + + Food + + Baking Goods + + Baking Goods + + All Gender + + M + + 4,352 + + 3,215.62 + + 8,133.08 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + All Gender + + 11,888 + + 9,247.29 + + 23,223.72 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jam + + All Gender + + 2,556 + + 2,132.27 + + 5,401.81 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jelly + + All Gender + + 2,565 + + 1,830.04 + + 4,609.61 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jelly + + All Gender + + F + + 1,309 + + 956.94 + + 2,414.94 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jelly + + All Gender + + M + + 1,256 + + 873.10 + + 2,194.67 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + All Gender + + 2,667 + + 2,097.37 + + 5,231.08 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + All Gender + + 556 + + 424.38 + + 1,055.72 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + All Gender + + F + + 271 + + 201.08 + + 500.39 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + All Gender + + M + + 285 + + 223.30 + + 555.33 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + BBB Best Chunky Peanut Butter + + All Gender + + 188 + + 147.32 + + 370.36 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + BBB Best Chunky Peanut Butter + + All Gender + + F + + 107 + + 85.81 + + 210.79 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + BBB Best Chunky Peanut Butter + + All Gender + + M + + 81 + + 61.50 + + 159.57 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + BBB Best Creamy Peanut Butter + + All Gender + + 201 + + 87.86 + + 221.10 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + BBB Best Creamy Peanut Butter + + All Gender + + F + + 99 + + 43.35 + + 108.90 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + BBB Best Creamy Peanut Butter + + All Gender + + M + + 102 + + 44.51 + + 112.20 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + BBB Best Extra Chunky Peanut Butter + + All Gender + + 167 + + 189.21 + + 464.26 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + BBB Best Extra Chunky Peanut Butter + + All Gender + + F + + 65 + + 71.92 + + 180.70 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + BBB Best Extra Chunky Peanut Butter + + All Gender + + M + + 102 + + 117.29 + + 283.56 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + CDR + + All Gender + + 545 + + 538.88 + + 1,326.30 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Landslide + + All Gender + + 531 + + 256.16 + + 635.29 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Plato + + All Gender + + 520 + + 447.73 + + 1,132.16 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Super + + All Gender + + 515 + + 430.21 + + 1,081.61 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Preserves + + All Gender + + 4,100 + + 3,187.61 + + 7,981.22 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Preserves + + All Gender + + F + + 1,946 + + 1,472.42 + + 3,717.80 +
      + All Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Preserves + + All Gender + + M + + 2,154 + + 1,715.19 + + 4,263.42 +
      + All Media + + All Products + + Food + + Breakfast Foods + + All Gender + + 3,317 + + 2,756.80 + + 6,941.46 +
      + All Media + + All Products + + Food + + Canned Foods + + All Gender + + 19,026 + + 15,894.53 + + 39,774.34 +
      + All Media + + All Products + + Food + + Canned Foods + + Canned Anchovies + + All Gender + + 900 + + 913.88 + + 2,296.38 +
      + All Media + + All Products + + Food + + Canned Foods + + Canned Clams + + All Gender + + 882 + + 759.80 + + 1,912.68 +
      + All Media + + All Products + + Food + + Canned Foods + + Canned Clams + + Clams + + All Gender + + 882 + + 759.80 + + 1,912.68 +
      + All Media + + All Products + + Food + + Canned Foods + + Canned Clams + + Clams + + Better + + All Gender + + 189 + + 151.14 + + 398.79 +
      + All Media + + All Products + + Food + + Canned Foods + + Canned Clams + + Clams + + Blue Label + + All Gender + + 165 + + 112.82 + + 278.85 +
      + All Media + + All Products + + Food + + Canned Foods + + Canned Clams + + Clams + + Bravo + + All Gender + + 184 + + 280.70 + + 708.40 +
      + All Media + + All Products + + Food + + Canned Foods + + Canned Clams + + Clams + + Just Right + + All Gender + + 177 + + 161.96 + + 394.71 +
      + All Media + + All Products + + Food + + Canned Foods + + Canned Clams + + Clams + + Pleasant + + All Gender + + 167 + + 53.17 + + 131.93 +
      + All Media + + All Products + + Food + + Canned Foods + + Canned Oysters + + All Gender + + 708 + + 571.50 + + 1,442.77 +
      + All Media + + All Products + + Food + + Canned Foods + + Canned Sardines + + All Gender + + 819 + + 537.59 + + 1,357.80 +
      + All Media + + All Products + + Food + + Canned Foods + + Canned Shrimp + + All Gender + + 804 + + 858.39 + + 2,146.49 +
      + All Media + + All Products + + Food + + Canned Foods + + Canned Soup + + All Gender + + 8,006 + + 6,408.29 + + 15,966.10 +
      + All Media + + All Products + + Food + + Canned Foods + + Canned Tuna + + All Gender + + 1,710 + + 1,288.52 + + 3,210.76 +
      + All Media + + All Products + + Food + + Canned Foods + + Vegetables + + All Gender + + 5,197 + + 4,556.57 + + 11,441.36 +
      + All Media + + All Products + + Food + + Canned Products + + All Gender + + 1,812 + + 1,317.13 + + 3,314.52 +
      + All Media + + All Products + + Food + + Dairy + + All Gender + + 12,885 + + 12,228.85 + + 30,508.85 +
      + All Media + + All Products + + Food + + Deli + + All Gender + + 12,037 + + 10,108.87 + + 25,318.93 +
      + All Media + + All Products + + Food + + Deli + + Meat + + All Gender + + 9,433 + + 8,215.81 + + 20,616.29 +
      + All Media + + All Products + + Food + + Deli + + Meat + + Bologna + + All Gender + + 2,588 + + 2,340.24 + + 5,859.95 +
      + All Media + + All Products + + Food + + Deli + + Meat + + Deli Meats + + All Gender + + 3,339 + + 2,851.18 + + 7,191.24 +
      + All Media + + All Products + + Food + + Deli + + Meat + + Deli Meats + + All Gender + + F + + 1,653 + + 1,414.49 + + 3,579.34 +
      + All Media + + All Products + + Food + + Deli + + Meat + + Deli Meats + + All Gender + + M + + 1,686 + + 1,436.69 + + 3,611.90 +
      + All Media + + All Products + + Food + + Deli + + Meat + + Fresh Chicken + + All Gender + + 878 + + 842.85 + + 2,091.52 +
      + All Media + + All Products + + Food + + Deli + + Meat + + Hot Dogs + + All Gender + + 2,628 + + 2,181.55 + + 5,473.58 +
      + All Media + + All Products + + Food + + Deli + + Side Dishes + + All Gender + + 2,604 + + 1,893.06 + + 4,702.64 +
      + All Media + + All Products + + Food + + Eggs + + All Gender + + 4,132 + + 3,684.90 + + 9,200.76 +
      + All Media + + All Products + + Food + + Frozen Foods + + All Gender + + 26,655 + + 22,030.66 + + 55,207.50 +
      + All Media + + All Products + + Food + + Meat + + All Gender + + 1,714 + + 1,465.42 + + 3,669.89 +
      + All Media + + All Products + + Food + + Produce + + All Gender + + 37,792 + + 32,831.33 + + 82,248.42 +
      + All Media + + All Products + + Food + + Seafood + + All Gender + + 1,764 + + 1,520.70 + + 3,809.14 +
      + All Media + + All Products + + Food + + Snack Foods + + All Gender + + 30,545 + + 26,963.34 + + 67,609.82 +
      + All Media + + All Products + + Food + + Snacks + + All Gender + + 6,884 + + 5,827.58 + + 14,550.05 +
      + All Media + + All Products + + Food + + Starchy Foods + + All Gender + + 5,262 + + 4,705.91 + + 11,756.07 +
      + All Media + + All Products + + Non-Consumable + + All Gender + + 50,236 + + 42,879.28 + + 107,366.33 +
      + All Media + + All Products + + Non-Consumable + + Carousel + + All Gender + + 841 + + 595.97 + + 1,500.11 +
      + All Media + + All Products + + Non-Consumable + + Checkout + + All Gender + + 1,779 + + 1,525.04 + + 3,767.71 +
      + All Media + + All Products + + Non-Consumable + + Health and Hygiene + + All Gender + + 16,284 + + 12,972.99 + + 32,571.86 +
      + All Media + + All Products + + Non-Consumable + + Household + + All Gender + + 27,038 + + 24,170.73 + + 60,469.89 +
      + All Media + + All Products + + Non-Consumable + + Periodicals + + All Gender + + 4,294 + + 3,614.55 + + 9,056.76 +
      + All Media + + Bulk Mail + + All Products + + All Gender + + 4,320 + + 3,740.95 + + 9,349.07 +
      + All Media + + Cash Register Handout + + All Products + + All Gender + + 6,697 + + 5,715.67 + + 14,321.33 +
      + All Media + + Daily Paper + + All Products + + All Gender + + 7,738 + + 6,559.23 + + 16,479.81 +
      + All Media + + Daily Paper, Radio + + All Products + + All Gender + + 6,891 + + 5,668.77 + + 14,169.42 +
      + All Media + + Daily Paper, Radio, TV + + All Products + + All Gender + + 9,513 + + 8,055.22 + + 20,173.97 +
      + All Media + + In-Store Coupon + + All Products + + All Gender + + 3,798 + + 3,263.11 + + 8,162.46 +
      + All Media + + In-Store Coupon + + All Products + + Drink + + All Gender + + 345 + + 282.44 + + 708.38 +
      + All Media + + In-Store Coupon + + All Products + + Food + + All Gender + + 2,737 + + 2,345.57 + + 5,889.34 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Baked Goods + + All Gender + + 131 + + 114.11 + + 279.11 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Baking Goods + + All Gender + + 308 + + 252.88 + + 632.01 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Baking Goods + + Baking Goods + + All Gender + + 146 + + 103.30 + + 261.44 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Baking Goods + + Jams and Jellies + + All Gender + + 162 + + 149.58 + + 370.57 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jam + + All Gender + + 55 + + 58.16 + + 141.19 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jelly + + All Gender + + 32 + + 23.96 + + 62.12 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + All Gender + + 22 + + 19.54 + + 48.72 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + All Gender + + 7 + + 6.72 + + 16.10 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + CDR + + All Gender + + 10 + + 9.81 + + 24.32 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Landslide + + All Gender + +   + +   + +   +
      + All Media + + In-Store Coupon + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Plato + + All Gender + + 3 + + 2.32 + + 6.32 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Super + + All Gender + + 2 + + .69 + + 1.98 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Preserves + + All Gender + + 53 + + 47.92 + + 118.54 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Breakfast Foods + + All Gender + + 59 + + 49.22 + + 125.19 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Breakfast Foods + + All Gender + + F + + 33 + + 22.88 + + 54.84 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Breakfast Foods + + All Gender + + M + + 26 + + 26.34 + + 70.35 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Canned Foods + + All Gender + + 245 + + 200.61 + + 506.67 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Canned Products + + All Gender + + 15 + + 9.58 + + 26.17 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Dairy + + All Gender + + 166 + + 153.42 + + 372.01 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Deli + + All Gender + + 180 + + 163.58 + + 392.68 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Eggs + + All Gender + + 56 + + 42.51 + + 108.90 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Frozen Foods + + All Gender + + 374 + + 301.63 + + 773.52 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Meat + + All Gender + + 31 + + 23.91 + + 70.35 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Produce + + All Gender + + 563 + + 499.63 + + 1,257.05 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Seafood + + All Gender + + 34 + + 30.06 + + 76.09 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Snack Foods + + All Gender + + 439 + + 390.35 + + 989.13 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Snacks + + All Gender + + 78 + + 63.77 + + 153.02 +
      + All Media + + In-Store Coupon + + All Products + + Food + + Starchy Foods + + All Gender + + 58 + + 50.30 + + 127.44 +
      + All Media + + In-Store Coupon + + All Products + + Non-Consumable + + All Gender + + 716 + + 635.10 + + 1,564.74 +
      + All Media + + In-Store Coupon + + All Products + + Non-Consumable + + Carousel + + All Gender + + 17 + + 8.77 + + 24.18 +
      + All Media + + In-Store Coupon + + All Products + + Non-Consumable + + Checkout + + All Gender + + 23 + + 15.20 + + 40.19 +
      + All Media + + In-Store Coupon + + All Products + + Non-Consumable + + Health and Hygiene + + All Gender + + 251 + + 193.53 + + 477.21 +
      + All Media + + In-Store Coupon + + All Products + + Non-Consumable + + Household + + All Gender + + 374 + + 375.66 + + 916.97 +
      + All Media + + In-Store Coupon + + All Products + + Non-Consumable + + Periodicals + + All Gender + + 51 + + 41.94 + + 106.19 +
      + All Media + + No Media + + All Products + + All Gender + + 195,448 + + 165,214.85 + + 414,026.92 +
      + All Media + + No Media + + All Products + + Drink + + All Gender + + 17,896 + + 14,211.41 + + 35,681.85 +
      + All Media + + No Media + + All Products + + Food + + All Gender + + 140,577 + + 119,469.36 + + 299,356.11 +
      + All Media + + No Media + + All Products + + Food + + Baked Goods + + All Gender + + 5,753 + + 4,775.86 + + 11,972.46 +
      + All Media + + No Media + + All Products + + Food + + Baking Goods + + All Gender + + 14,849 + + 11,226.15 + + 28,312.78 +
      + All Media + + No Media + + All Products + + Food + + Baking Goods + + Baking Goods + + All Gender + + 5,979 + + 4,347.34 + + 11,002.73 +
      + All Media + + No Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + All Gender + + 8,870 + + 6,878.81 + + 17,310.05 +
      + All Media + + No Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jam + + All Gender + + 1,883 + + 1,554.13 + + 3,965.74 +
      + All Media + + No Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jelly + + All Gender + + 1,936 + + 1,394.32 + + 3,504.71 +
      + All Media + + No Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + All Gender + + 1,984 + + 1,534.19 + + 3,828.01 +
      + All Media + + No Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + All Gender + + 406 + + 293.97 + + 735.29 +
      + All Media + + No Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + CDR + + All Gender + + 411 + + 401.88 + + 998.12 +
      + All Media + + No Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Landslide + + All Gender + + 401 + + 195.51 + + 478.44 +
      + All Media + + No Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Plato + + All Gender + + 384 + + 331.26 + + 832.92 +
      + All Media + + No Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Super + + All Gender + + 382 + + 311.57 + + 783.24 +
      + All Media + + No Media + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Preserves + + All Gender + + 3,067 + + 2,396.16 + + 6,011.59 +
      + All Media + + No Media + + All Products + + Food + + Breakfast Foods + + All Gender + + 2,418 + + 1,996.45 + + 5,016.10 +
      + All Media + + No Media + + All Products + + Food + + Canned Foods + + All Gender + + 13,861 + + 11,647.47 + + 29,102.79 +
      + All Media + + No Media + + All Products + + Food + + Canned Products + + All Gender + + 1,344 + + 960.82 + + 2,424.98 +
      + All Media + + No Media + + All Products + + Food + + Dairy + + All Gender + + 9,510 + + 8,981.13 + + 22,454.02 +
      + All Media + + No Media + + All Products + + Food + + Deli + + All Gender + + 8,695 + + 7,353.56 + + 18,410.26 +
      + All Media + + No Media + + All Products + + Food + + Eggs + + All Gender + + 2,976 + + 2,640.47 + + 6,606.25 +
      + All Media + + No Media + + All Products + + Food + + Frozen Foods + + All Gender + + 19,450 + + 16,127.24 + + 40,411.08 +
      + All Media + + No Media + + All Products + + Food + + Meat + + All Gender + + 1,236 + + 1,068.07 + + 2,646.00 +
      + All Media + + No Media + + All Products + + Food + + Produce + + All Gender + + 27,637 + + 24,036.36 + + 60,203.58 +
      + All Media + + No Media + + All Products + + Food + + Seafood + + All Gender + + 1,292 + + 1,114.69 + + 2,774.43 +
      + All Media + + No Media + + All Products + + Food + + Snack Foods + + All Gender + + 22,525 + + 19,800.82 + + 49,680.71 +
      + All Media + + No Media + + All Products + + Food + + Snacks + + All Gender + + 5,100 + + 4,264.55 + + 10,690.26 +
      + All Media + + No Media + + All Products + + Food + + Starchy Foods + + All Gender + + 3,931 + + 3,475.74 + + 8,650.41 +
      + All Media + + No Media + + All Products + + Non-Consumable + + All Gender + + 36,975 + + 31,534.08 + + 78,988.96 +
      + All Media + + No Media + + All Products + + Non-Consumable + + Carousel + + All Gender + + 584 + + 419.65 + + 1,050.75 +
      + All Media + + No Media + + All Products + + Non-Consumable + + Checkout + + All Gender + + 1,305 + + 1,113.97 + + 2,768.66 +
      + All Media + + No Media + + All Products + + Non-Consumable + + Health and Hygiene + + All Gender + + 11,845 + + 9,413.25 + + 23,621.12 +
      + All Media + + No Media + + All Products + + Non-Consumable + + Household + + All Gender + + 20,091 + + 17,929.20 + + 44,881.13 +
      + All Media + + No Media + + All Products + + Non-Consumable + + Periodicals + + All Gender + + 3,150 + + 2,658.00 + + 6,667.30 +
      + All Media + + Product Attachment + + All Products + + All Gender + + 7,544 + + 6,306.24 + + 15,898.25 +
      + All Media + + Product Attachment + + All Products + + Drink + + All Gender + + 713 + + 555.05 + + 1,403.65 +
      + All Media + + Product Attachment + + All Products + + Food + + All Gender + + 5,441 + + 4,571.71 + + 11,525.25 +
      + All Media + + Product Attachment + + All Products + + Food + + Baked Goods + + All Gender + + 213 + + 175.69 + + 445.60 +
      + All Media + + Product Attachment + + All Products + + Food + + Baking Goods + + All Gender + + 547 + + 410.31 + + 1,032.59 +
      + All Media + + Product Attachment + + All Products + + Food + + Baking Goods + + Baking Goods + + All Gender + + 258 + + 191.48 + + 470.58 +
      + All Media + + Product Attachment + + All Products + + Food + + Baking Goods + + Jams and Jellies + + All Gender + + 289 + + 218.83 + + 562.01 +
      + All Media + + Product Attachment + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jam + + All Gender + + 66 + + 48.03 + + 128.68 +
      + All Media + + Product Attachment + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jelly + + All Gender + + 45 + + 34.12 + + 90.62 +
      + All Media + + Product Attachment + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + All Gender + + 63 + + 47.71 + + 122.31 +
      + All Media + + Product Attachment + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + All Gender + + 15 + + 14.53 + + 38.46 +
      + All Media + + Product Attachment + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + CDR + + All Gender + + 13 + + 11.94 + + 30.57 +
      + All Media + + Product Attachment + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Landslide + + All Gender + + 12 + + 5.32 + + 14.28 +
      + All Media + + Product Attachment + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Plato + + All Gender + + 9 + + 7.16 + + 17.43 +
      + All Media + + Product Attachment + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Super + + All Gender + + 14 + + 8.75 + + 21.57 +
      + All Media + + Product Attachment + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Preserves + + All Gender + + 115 + + 88.98 + + 220.40 +
      + All Media + + Product Attachment + + All Products + + Food + + Breakfast Foods + + All Gender + + 103 + + 87.35 + + 220.75 +
      + All Media + + Product Attachment + + All Products + + Food + + Canned Foods + + All Gender + + 564 + + 463.28 + + 1,154.91 +
      + All Media + + Product Attachment + + All Products + + Food + + Canned Products + + All Gender + + 60 + + 51.61 + + 124.24 +
      + All Media + + Product Attachment + + All Products + + Food + + Dairy + + All Gender + + 355 + + 339.81 + + 849.78 +
      + All Media + + Product Attachment + + All Products + + Food + + Deli + + All Gender + + 324 + + 243.64 + + 618.23 +
      + All Media + + Product Attachment + + All Products + + Food + + Eggs + + All Gender + + 118 + + 97.43 + + 241.21 +
      + All Media + + Product Attachment + + All Products + + Food + + Frozen Foods + + All Gender + + 812 + + 665.48 + + 1,692.11 +
      + All Media + + Product Attachment + + All Products + + Food + + Meat + + All Gender + + 54 + + 51.36 + + 127.83 +
      + All Media + + Product Attachment + + All Products + + Food + + Produce + + All Gender + + 1,069 + + 909.24 + + 2,287.61 +
      + All Media + + Product Attachment + + All Products + + Food + + Seafood + + All Gender + + 45 + + 36.98 + + 100.61 +
      + All Media + + Product Attachment + + All Products + + Food + + Snack Foods + + All Gender + + 819 + + 726.73 + + 1,847.28 +
      + All Media + + Product Attachment + + All Products + + Food + + Snacks + + All Gender + + 209 + + 186.22 + + 450.03 +
      + All Media + + Product Attachment + + All Products + + Food + + Starchy Foods + + All Gender + + 149 + + 126.59 + + 332.47 +
      + All Media + + Product Attachment + + All Products + + Non-Consumable + + All Gender + + 1,390 + + 1,179.48 + + 2,969.35 +
      + All Media + + Product Attachment + + All Products + + Non-Consumable + + Carousel + + All Gender + + 14 + + 7.99 + + 21.21 +
      + All Media + + Product Attachment + + All Products + + Non-Consumable + + Checkout + + All Gender + + 48 + + 40.45 + + 100.61 +
      + All Media + + Product Attachment + + All Products + + Non-Consumable + + Health and Hygiene + + All Gender + + 440 + + 356.54 + + 901.73 +
      + All Media + + Product Attachment + + All Products + + Non-Consumable + + Household + + All Gender + + 777 + + 690.03 + + 1,737.96 +
      + All Media + + Product Attachment + + All Products + + Non-Consumable + + Periodicals + + All Gender + + 111 + + 84.48 + + 207.84 +
      + All Media + + Radio + + All Products + + All Gender + + 2,454 + + 2,087.51 + + 5,213.61 +
      + All Media + + Radio + + All Products + + Drink + + All Gender + + 226 + + 182.85 + + 443.68 +
      + All Media + + Radio + + All Products + + Food + + All Gender + + 1,733 + + 1,485.25 + + 3,727.36 +
      + All Media + + Radio + + All Products + + Food + + Baked Goods + + All Gender + + 83 + + 76.51 + + 186.20 +
      + All Media + + Radio + + All Products + + Food + + Baking Goods + + All Gender + + 157 + + 109.10 + + 274.90 +
      + All Media + + Radio + + All Products + + Food + + Baking Goods + + Baking Goods + + All Gender + + 63 + + 45.02 + + 110.43 +
      + All Media + + Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + All Gender + + 94 + + 64.08 + + 164.47 +
      + All Media + + Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jam + + All Gender + + 15 + + 10.42 + + 26.94 +
      + All Media + + Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jelly + + All Gender + + 24 + + 14.54 + + 37.49 +
      + All Media + + Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + All Gender + + 19 + + 16.85 + + 41.82 +
      + All Media + + Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + All Gender + + 10 + + 10.58 + + 24.44 +
      + All Media + + Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + CDR + + All Gender + +   + +   + +   +
      + All Media + + Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Landslide + + All Gender + +   + +   + +   +
      + All Media + + Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Plato + + All Gender + + 4 + + 3.77 + + 9.80 +
      + All Media + + Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Super + + All Gender + + 5 + + 2.50 + + 7.58 +
      + All Media + + Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Preserves + + All Gender + + 36 + + 22.28 + + 58.22 +
      + All Media + + Radio + + All Products + + Food + + Breakfast Foods + + All Gender + + 25 + + 18.78 + + 50.22 +
      + All Media + + Radio + + All Products + + Food + + Canned Foods + + All Gender + + 158 + + 124.79 + + 307.55 +
      + All Media + + Radio + + All Products + + Food + + Canned Products + + All Gender + + 22 + + 17.29 + + 43.42 +
      + All Media + + Radio + + All Products + + Food + + Dairy + + All Gender + + 112 + + 92.12 + + 216.79 +
      + All Media + + Radio + + All Products + + Food + + Deli + + All Gender + + 129 + + 119.14 + + 307.25 +
      + All Media + + Radio + + All Products + + Food + + Eggs + + All Gender + + 25 + + 29.97 + + 71.15 +
      + All Media + + Radio + + All Products + + Food + + Frozen Foods + + All Gender + + 253 + + 202.71 + + 507.45 +
      + All Media + + Radio + + All Products + + Food + + Meat + + All Gender + + 12 + + 11.53 + + 32.85 +
      + All Media + + Radio + + All Products + + Food + + Produce + + All Gender + + 336 + + 292.05 + + 738.20 +
      + All Media + + Radio + + All Products + + Food + + Seafood + + All Gender + + 15 + + 13.28 + + 35.58 +
      + All Media + + Radio + + All Products + + Food + + Snack Foods + + All Gender + + 290 + + 270.59 + + 674.73 +
      + All Media + + Radio + + All Products + + Food + + Snacks + + All Gender + + 60 + + 55.67 + + 144.58 +
      + All Media + + Radio + + All Products + + Food + + Starchy Foods + + All Gender + + 56 + + 51.72 + + 136.49 +
      + All Media + + Radio + + All Products + + Non-Consumable + + All Gender + + 495 + + 419.41 + + 1,042.57 +
      + All Media + + Radio + + All Products + + Non-Consumable + + Carousel + + All Gender + + 15 + + 11.15 + + 26.85 +
      + All Media + + Radio + + All Products + + Non-Consumable + + Checkout + + All Gender + + 21 + + 17.00 + + 42.74 +
      + All Media + + Radio + + All Products + + Non-Consumable + + Health and Hygiene + + All Gender + + 145 + + 114.84 + + 289.80 +
      + All Media + + Radio + + All Products + + Non-Consumable + + Household + + All Gender + + 258 + + 233.31 + + 575.07 +
      + All Media + + Radio + + All Products + + Non-Consumable + + Periodicals + + All Gender + + 56 + + 43.12 + + 108.11 +
      + All Media + + Street Handout + + All Products + + All Gender + + 5,753 + + 4,856.54 + + 12,192.90 +
      + All Media + + Street Handout + + All Products + + Drink + + All Gender + + 512 + + 372.68 + + 943.42 +
      + All Media + + Street Handout + + All Products + + Food + + All Gender + + 4,239 + + 3,650.32 + + 9,151.65 +
      + All Media + + Street Handout + + All Products + + Food + + Baked Goods + + All Gender + + 160 + + 120.12 + + 301.62 +
      + All Media + + Street Handout + + All Products + + Food + + Baking Goods + + All Gender + + 498 + + 373.67 + + 923.22 +
      + All Media + + Street Handout + + All Products + + Food + + Baking Goods + + Baking Goods + + All Gender + + 200 + + 144.16 + + 357.82 +
      + All Media + + Street Handout + + All Products + + Food + + Baking Goods + + Jams and Jellies + + All Gender + + 298 + + 229.51 + + 565.40 +
      + All Media + + Street Handout + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jam + + All Gender + + 53 + + 44.30 + + 112.95 +
      + All Media + + Street Handout + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jelly + + All Gender + + 92 + + 63.14 + + 155.59 +
      + All Media + + Street Handout + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + All Gender + + 51 + + 51.06 + + 118.90 +
      + All Media + + Street Handout + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + All Gender + + 11 + + 10.85 + + 25.72 +
      + All Media + + Street Handout + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + CDR + + All Gender + + 8 + + 9.06 + + 19.73 +
      + All Media + + Street Handout + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Landslide + + All Gender + + 11 + + 6.90 + + 15.54 +
      + All Media + + Street Handout + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Plato + + All Gender + + 9 + + 8.47 + + 20.89 +
      + All Media + + Street Handout + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Super + + All Gender + + 12 + + 15.78 + + 37.02 +
      + All Media + + Street Handout + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Preserves + + All Gender + + 102 + + 71.02 + + 177.96 +
      + All Media + + Street Handout + + All Products + + Food + + Breakfast Foods + + All Gender + + 81 + + 74.32 + + 192.90 +
      + All Media + + Street Handout + + All Products + + Food + + Canned Foods + + All Gender + + 459 + + 413.21 + + 1,021.86 +
      + All Media + + Street Handout + + All Products + + Food + + Canned Products + + All Gender + + 30 + + 19.43 + + 45.68 +
      + All Media + + Street Handout + + All Products + + Food + + Dairy + + All Gender + + 301 + + 285.98 + + 718.61 +
      + All Media + + Street Handout + + All Products + + Food + + Deli + + All Gender + + 305 + + 253.54 + + 638.30 +
      + All Media + + Street Handout + + All Products + + Food + + Eggs + + All Gender + + 66 + + 59.15 + + 156.82 +
      + All Media + + Street Handout + + All Products + + Food + + Frozen Foods + + All Gender + + 612 + + 520.12 + + 1,313.71 +
      + All Media + + Street Handout + + All Products + + Food + + Meat + + All Gender + + 37 + + 29.82 + + 78.24 +
      + All Media + + Street Handout + + All Products + + Food + + Produce + + All Gender + + 745 + + 662.39 + + 1,639.94 +
      + All Media + + Street Handout + + All Products + + Food + + Seafood + + All Gender + + 37 + + 30.12 + + 72.77 +
      + All Media + + Street Handout + + All Products + + Food + + Snack Foods + + All Gender + + 675 + + 600.23 + + 1,515.68 +
      + All Media + + Street Handout + + All Products + + Food + + Snacks + + All Gender + + 144 + + 128.79 + + 321.16 +
      + All Media + + Street Handout + + All Products + + Food + + Starchy Foods + + All Gender + + 89 + + 79.43 + + 211.14 +
      + All Media + + Street Handout + + All Products + + Non-Consumable + + All Gender + + 1,002 + + 833.53 + + 2,097.83 +
      + All Media + + Street Handout + + All Products + + Non-Consumable + + Carousel + + All Gender + + 17 + + 13.53 + + 30.98 +
      + All Media + + Street Handout + + All Products + + Non-Consumable + + Checkout + + All Gender + + 45 + + 34.77 + + 85.38 +
      + All Media + + Street Handout + + All Products + + Non-Consumable + + Health and Hygiene + + All Gender + + 402 + + 318.03 + + 802.92 +
      + All Media + + Street Handout + + All Products + + Non-Consumable + + Household + + All Gender + + 501 + + 436.41 + + 1,105.38 +
      + All Media + + Street Handout + + All Products + + Non-Consumable + + Periodicals + + All Gender + + 37 + + 30.80 + + 73.17 +
      + All Media + + Sunday Paper + + All Products + + All Gender + + 4,339 + + 3,673.86 + + 9,092.89 +
      + All Media + + Sunday Paper + + All Products + + Drink + + All Gender + + 430 + + 345.53 + + 856.73 +
      + All Media + + Sunday Paper + + All Products + + Food + + All Gender + + 3,106 + + 2,646.47 + + 6,559.46 +
      + All Media + + Sunday Paper + + All Products + + Food + + Baked Goods + + All Gender + + 140 + + 110.79 + + 282.55 +
      + All Media + + Sunday Paper + + All Products + + Food + + Baking Goods + + All Gender + + 338 + + 239.76 + + 603.86 +
      + All Media + + Sunday Paper + + All Products + + Food + + Baking Goods + + Baking Goods + + All Gender + + 170 + + 118.05 + + 298.79 +
      + All Media + + Sunday Paper + + All Products + + Food + + Baking Goods + + Jams and Jellies + + All Gender + + 168 + + 121.71 + + 305.07 +
      + All Media + + Sunday Paper + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jam + + All Gender + + 24 + + 22.35 + + 54.83 +
      + All Media + + Sunday Paper + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jelly + + All Gender + + 27 + + 18.20 + + 47.12 +
      + All Media + + Sunday Paper + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + All Gender + + 51 + + 37.67 + + 96.67 +
      + All Media + + Sunday Paper + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + All Gender + + 10 + + 6.08 + + 16.22 +
      + All Media + + Sunday Paper + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + CDR + + All Gender + + 10 + + 10.47 + + 26.50 +
      + All Media + + Sunday Paper + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Landslide + + All Gender + + 15 + + 6.20 + + 16.31 +
      + All Media + + Sunday Paper + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Plato + + All Gender + + 16 + + 14.93 + + 37.64 +
      + All Media + + Sunday Paper + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Super + + All Gender + +   + +   + +   +
      + All Media + + Sunday Paper + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Preserves + + All Gender + + 66 + + 43.49 + + 106.45 +
      + All Media + + Sunday Paper + + All Products + + Food + + Breakfast Foods + + All Gender + + 55 + + 49.80 + + 120.23 +
      + All Media + + Sunday Paper + + All Products + + Food + + Canned Foods + + All Gender + + 283 + + 249.46 + + 605.11 +
      + All Media + + Sunday Paper + + All Products + + Food + + Canned Products + + All Gender + + 34 + + 29.65 + + 72.18 +
      + All Media + + Sunday Paper + + All Products + + Food + + Dairy + + All Gender + + 200 + + 201.94 + + 497.91 +
      + All Media + + Sunday Paper + + All Products + + Food + + Deli + + All Gender + + 228 + + 188.37 + + 467.53 +
      + All Media + + Sunday Paper + + All Products + + Food + + Eggs + + All Gender + + 54 + + 47.68 + + 118.44 +
      + All Media + + Sunday Paper + + All Products + + Food + + Frozen Foods + + All Gender + + 425 + + 330.81 + + 839.15 +
      + All Media + + Sunday Paper + + All Products + + Food + + Meat + + All Gender + + 18 + + 19.85 + + 52.20 +
      + All Media + + Sunday Paper + + All Products + + Food + + Produce + + All Gender + + 603 + + 520.95 + + 1,274.70 +
      + All Media + + Sunday Paper + + All Products + + Food + + Seafood + + All Gender + + 27 + + 26.82 + + 69.49 +
      + All Media + + Sunday Paper + + All Products + + Food + + Snack Foods + + All Gender + + 469 + + 413.18 + + 1,027.98 +
      + All Media + + Sunday Paper + + All Products + + Food + + Snacks + + All Gender + + 123 + + 108.50 + + 261.38 +
      + All Media + + Sunday Paper + + All Products + + Food + + Starchy Foods + + All Gender + + 109 + + 108.91 + + 266.75 +
      + All Media + + Sunday Paper + + All Products + + Non-Consumable + + All Gender + + 803 + + 681.86 + + 1,676.70 +
      + All Media + + Sunday Paper + + All Products + + Non-Consumable + + Carousel + + All Gender + + 7 + + 6.70 + + 14.68 +
      + All Media + + Sunday Paper + + All Products + + Non-Consumable + + Checkout + + All Gender + + 17 + + 13.09 + + 30.89 +
      + All Media + + Sunday Paper + + All Products + + Non-Consumable + + Health and Hygiene + + All Gender + + 278 + + 227.06 + + 565.99 +
      + All Media + + Sunday Paper + + All Products + + Non-Consumable + + Household + + All Gender + + 420 + + 371.58 + + 911.69 +
      + All Media + + Sunday Paper + + All Products + + Non-Consumable + + Periodicals + + All Gender + + 81 + + 63.43 + + 153.45 +
      + All Media + + Sunday Paper, Radio + + All Products + + All Gender + + 5,945 + + 5,027.31 + + 12,551.96 +
      + All Media + + Sunday Paper, Radio + + All Products + + Drink + + All Gender + + 591 + + 454.03 + + 1,129.94 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + All Gender + + 4,239 + + 3,612.38 + + 9,033.23 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Baked Goods + + All Gender + + 152 + + 109.11 + + 274.39 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Baking Goods + + All Gender + + 482 + + 367.13 + + 913.84 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Baking Goods + + Baking Goods + + All Gender + + 206 + + 152.72 + + 381.59 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + All Gender + + 276 + + 214.41 + + 532.25 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jam + + All Gender + + 52 + + 52.39 + + 126.62 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jelly + + All Gender + + 74 + + 53.93 + + 135.03 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + All Gender + + 64 + + 50.10 + + 126.71 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + All Gender + + 14 + + 11.58 + + 27.40 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + CDR + + All Gender + + 17 + + 14.68 + + 41.25 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Landslide + + All Gender + + 14 + + 6.62 + + 17.04 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Plato + + All Gender + + 7 + + 6.91 + + 17.15 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Super + + All Gender + + 12 + + 10.31 + + 23.87 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Preserves + + All Gender + + 86 + + 57.99 + + 143.89 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Breakfast Foods + + All Gender + + 80 + + 62.80 + + 154.04 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Canned Foods + + All Gender + + 456 + + 361.79 + + 914.81 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Canned Products + + All Gender + + 45 + + 39.72 + + 95.88 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Dairy + + All Gender + + 283 + + 296.91 + + 722.75 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Deli + + All Gender + + 252 + + 190.32 + + 479.59 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Eggs + + All Gender + + 114 + + 104.65 + + 256.15 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Frozen Foods + + All Gender + + 599 + + 490.33 + + 1,222.54 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Meat + + All Gender + + 40 + + 31.66 + + 84.76 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Produce + + All Gender + + 858 + + 752.62 + + 1,886.01 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Seafood + + All Gender + + 27 + + 20.66 + + 50.39 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Snack Foods + + All Gender + + 596 + + 555.70 + + 1,402.21 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Snacks + + All Gender + + 147 + + 120.43 + + 304.18 +
      + All Media + + Sunday Paper, Radio + + All Products + + Food + + Starchy Foods + + All Gender + + 108 + + 108.55 + + 271.69 +
      + All Media + + Sunday Paper, Radio + + All Products + + Non-Consumable + + All Gender + + 1,115 + + 960.90 + + 2,388.79 +
      + All Media + + Sunday Paper, Radio + + All Products + + Non-Consumable + + Carousel + + All Gender + + 18 + + 10.99 + + 26.94 +
      + All Media + + Sunday Paper, Radio + + All Products + + Non-Consumable + + Checkout + + All Gender + + 26 + + 24.68 + + 62.14 +
      + All Media + + Sunday Paper, Radio + + All Products + + Non-Consumable + + Health and Hygiene + + All Gender + + 378 + + 309.37 + + 771.48 +
      + All Media + + Sunday Paper, Radio + + All Products + + Non-Consumable + + Household + + All Gender + + 585 + + 516.99 + + 1,276.16 +
      + All Media + + Sunday Paper, Radio + + All Products + + Non-Consumable + + Periodicals + + All Gender + + 108 + + 98.86 + + 252.07 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + All Gender + + 2,726 + + 2,341.58 + + 5,819.33 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Drink + + All Gender + + 225 + + 163.09 + + 403.51 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + All Gender + + 2,021 + + 1,762.18 + + 4,377.85 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Baked Goods + + All Gender + + 67 + + 66.17 + + 163.29 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Baking Goods + + All Gender + + 228 + + 182.98 + + 455.90 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Baking Goods + + Baking Goods + + All Gender + + 90 + + 73.09 + + 176.63 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + All Gender + + 138 + + 109.90 + + 279.27 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jam + + All Gender + + 37 + + 31.30 + + 78.56 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jelly + + All Gender + + 27 + + 16.18 + + 39.92 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + All Gender + + 30 + + 24.01 + + 64.19 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + All Gender + + 11 + + 9.78 + + 23.86 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + CDR + + All Gender + +   + +   + +   +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Landslide + + All Gender + + 4 + + 2.39 + + 5.68 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Plato + + All Gender + + 5 + + 3.85 + + 11.60 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Super + + All Gender + + 10 + + 7.99 + + 23.05 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Preserves + + All Gender + + 44 + + 38.41 + + 96.60 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Breakfast Foods + + All Gender + + 38 + + 32.76 + + 89.85 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Canned Foods + + All Gender + + 180 + + 138.77 + + 340.04 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Canned Products + + All Gender + + 14 + + 12.00 + + 28.28 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Dairy + + All Gender + + 121 + + 125.32 + + 305.43 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Deli + + All Gender + + 131 + + 98.93 + + 245.42 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Eggs + + All Gender + + 39 + + 39.57 + + 91.99 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Frozen Foods + + All Gender + + 279 + + 207.59 + + 514.95 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Meat + + All Gender + + 12 + + 11.77 + + 30.23 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Produce + + All Gender + + 411 + + 382.14 + + 943.93 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Seafood + + All Gender + + 31 + + 28.07 + + 69.82 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Snack Foods + + All Gender + + 346 + + 318.26 + + 798.50 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Snacks + + All Gender + + 75 + + 65.49 + + 174.02 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Food + + Starchy Foods + + All Gender + + 49 + + 52.37 + + 126.20 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Non-Consumable + + All Gender + + 480 + + 416.30 + + 1,037.97 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Non-Consumable + + Carousel + + All Gender + + 21 + + 11.63 + + 27.92 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Non-Consumable + + Checkout + + All Gender + + 10 + + 8.12 + + 19.80 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Non-Consumable + + Health and Hygiene + + All Gender + + 138 + + 110.35 + + 276.31 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Non-Consumable + + Household + + All Gender + + 262 + + 244.90 + + 608.52 +
      + All Media + + Sunday Paper, Radio, TV + + All Products + + Non-Consumable + + Periodicals + + All Gender + + 49 + + 41.30 + + 105.42 +
      + All Media + + TV + + All Products + + All Gender + + 3,607 + + 3,116.40 + + 7,786.21 +
      + All Media + + TV + + All Products + + Drink + + All Gender + + 332 + + 283.18 + + 721.07 +
      + All Media + + TV + + All Products + + Food + + All Gender + + 2,563 + + 2,238.13 + + 5,573.27 +
      + All Media + + TV + + All Products + + Food + + Baked Goods + + All Gender + + 114 + + 103.40 + + 262.97 +
      + All Media + + TV + + All Products + + Food + + Baking Goods + + All Gender + + 237 + + 185.55 + + 464.23 +
      + All Media + + TV + + All Products + + Food + + Baking Goods + + Baking Goods + + All Gender + + 95 + + 74.29 + + 190.59 +
      + All Media + + TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + All Gender + + 142 + + 111.25 + + 273.64 +
      + All Media + + TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jam + + All Gender + + 38 + + 32.28 + + 77.58 +
      + All Media + + TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Jelly + + All Gender + + 35 + + 24.64 + + 63.38 +
      + All Media + + TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + All Gender + + 31 + + 21.83 + + 56.80 +
      + All Media + + TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + BBB Best + + All Gender + +   + +   + +   +
      + All Media + + TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + CDR + + All Gender + + 11 + + 9.78 + + 27.19 +
      + All Media + + TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Landslide + + All Gender + + 7 + + 2.61 + + 7.12 +
      + All Media + + TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Plato + + All Gender + + 6 + + 4.95 + + 12.13 +
      + All Media + + TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Peanut Butter + + Super + + All Gender + + 7 + + 4.48 + + 10.36 +
      + All Media + + TV + + All Products + + Food + + Baking Goods + + Jams and Jellies + + Preserves + + All Gender + + 38 + + 32.51 + + 75.88 +
      + All Media + + TV + + All Products + + Food + + Breakfast Foods + + All Gender + + 36 + + 30.11 + + 79.89 +
      + All Media + + TV + + All Products + + Food + + Canned Foods + + All Gender + + 240 + + 200.00 + + 519.91 +
      + All Media + + TV + + All Products + + Food + + Canned Products + + All Gender + + 26 + + 15.00 + + 38.65 +
      + All Media + + TV + + All Products + + Food + + Dairy + + All Gender + + 179 + + 183.73 + + 458.87 +
      + All Media + + TV + + All Products + + Food + + Deli + + All Gender + + 155 + + 139.76 + + 342.51 +
      + All Media + + TV + + All Products + + Food + + Eggs + + All Gender + + 42 + + 32.74 + + 80.93 +
      + All Media + + TV + + All Products + + Food + + Frozen Foods + + All Gender + + 352 + + 300.42 + + 738.40 +
      + All Media + + TV + + All Products + + Food + + Meat + + All Gender + + 22 + + 19.76 + + 49.27 +
      + All Media + + TV + + All Products + + Food + + Produce + + All Gender + + 543 + + 456.53 + + 1,145.45 +
      + All Media + + TV + + All Products + + Food + + Seafood + + All Gender + + 34 + + 30.71 + + 75.47 +
      + All Media + + TV + + All Products + + Food + + Snack Foods + + All Gender + + 401 + + 377.01 + + 927.50 +
      + All Media + + TV + + All Products + + Food + + Snacks + + All Gender + + 99 + + 92.80 + + 220.54 +
      + All Media + + TV + + All Products + + Food + + Starchy Foods + + All Gender + + 83 + + 70.61 + + 168.68 +
      + All Media + + TV + + All Products + + Non-Consumable + + All Gender + + 712 + + 595.08 + + 1,491.87 +
      + All Media + + TV + + All Products + + Non-Consumable + + Carousel + + All Gender + + 4 + + 3.13 + + 9.20 +
      + All Media + + TV + + All Products + + Non-Consumable + + Checkout + + All Gender + + 34 + + 34.12 + + 86.21 +
      + All Media + + TV + + All Products + + Non-Consumable + + Health and Hygiene + + All Gender + + 249 + + 196.08 + + 486.46 +
      + All Media + + TV + + All Products + + Non-Consumable + + Household + + All Gender + + 361 + + 316.09 + + 795.40 +
      + All Media + + TV + + All Products + + Non-Consumable + + Periodicals + + All Gender + + 64 + + 45.67 + + 114.60 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/member-properties-false-false-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/member-properties-false-false-false-result.html index 167532fb..7abd8c26 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/member-properties-false-false-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/member-properties-false-false-false-result.html @@ -1,788 +1,788 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - All Products -
      - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - All Stores - -   - -   - -   - -   - -   - -   - -   - -   - - 266,773 - - 225,627.23 - - 565,238.13 -
      - Canada - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   -
      - BC - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   -
      - Vancouver - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   -
      - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - -   - -   - -   -
      - Victoria - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   -
      - Store 20 - - Mid-Size Grocery - - Cobb - - 34452 - - 27463 - - 4193 - - 2795 - - 1 - - 3706 Marvelle Ln - -   - -   - -   -
      - Mexico - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   -
      - USA - -   - -   - -   - -   - -   - -   - -   - -   - - 266,773 - - 225,627.23 - - 565,238.13 -
      - CA - -   - -   - -   - -   - -   - -   - -   - -   - - 74,748 - - 63,530.43 - - 159,167.84 -
      - Alameda - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   -
      - HQ - - HeadQuarters - -   - -   - -   - -   - -   - - 0 - - 1 Alameda Way - -   - -   - -   -
      - Beverly Hills - -   - -   - -   - -   - -   - -   - -   - -   - - 21,333 - - 18,266.44 - - 45,750.24 -
      - Store 6 - - Gourmet Supermarket - - Maris - - 23688 - - 15337 - - 5011 - - 3340 - - 1 - - 5495 Mitchell Canyon Road - - 21,333 - - 18,266.44 - - 45,750.24 -
      - Los Angeles - -   - -   - -   - -   - -   - -   - -   - -   - - 25,663 - - 21,771.54 - - 54,545.28 -
      - San Diego - -   - -   - -   - -   - -   - -   - -   - -   - - 25,635 - - 21,713.53 - - 54,431.14 -
      - Store 24 - - Supermarket - - Byrd - -   - -   - -   - -   - - 1 - - 2342 Waltham St. - - 25,635 - - 21,713.53 - - 54,431.14 -
      - San Francisco - -   - -   - -   - -   - -   - -   - -   - -   - - 2,117 - - 1,778.92 - - 4,441.18 -
      - OR - -   - -   - -   - -   - -   - -   - -   - -   - - 67,659 - - 56,772.50 - - 142,277.07 -
      - WA - -   - -   - -   - -   - -   - -   - -   - -   - - 124,366 - - 105,324.31 - - 263,793.22 -
      +   + + All Products +
      + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + All Stores + +   + +   + +   + +   + +   + +   + +   + +   + + 266,773 + + 225,627.23 + + 565,238.13 +
      + Canada + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   +
      + BC + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   +
      + Vancouver + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   +
      + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + +   + +   + +   +
      + Victoria + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   +
      + Store 20 + + Mid-Size Grocery + + Cobb + + 34452 + + 27463 + + 4193 + + 2795 + + 1 + + 3706 Marvelle Ln + +   + +   + +   +
      + Mexico + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   +
      + USA + +   + +   + +   + +   + +   + +   + +   + +   + + 266,773 + + 225,627.23 + + 565,238.13 +
      + CA + +   + +   + +   + +   + +   + +   + +   + +   + + 74,748 + + 63,530.43 + + 159,167.84 +
      + Alameda + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   +
      + HQ + + HeadQuarters + +   + +   + +   + +   + +   + + 0 + + 1 Alameda Way + +   + +   + +   +
      + Beverly Hills + +   + +   + +   + +   + +   + +   + +   + +   + + 21,333 + + 18,266.44 + + 45,750.24 +
      + Store 6 + + Gourmet Supermarket + + Maris + + 23688 + + 15337 + + 5011 + + 3340 + + 1 + + 5495 Mitchell Canyon Road + + 21,333 + + 18,266.44 + + 45,750.24 +
      + Los Angeles + +   + +   + +   + +   + +   + +   + +   + +   + + 25,663 + + 21,771.54 + + 54,545.28 +
      + San Diego + +   + +   + +   + +   + +   + +   + +   + +   + + 25,635 + + 21,713.53 + + 54,431.14 +
      + Store 24 + + Supermarket + + Byrd + +   + +   + +   + +   + + 1 + + 2342 Waltham St. + + 25,635 + + 21,713.53 + + 54,431.14 +
      + San Francisco + +   + +   + +   + +   + +   + +   + +   + +   + + 2,117 + + 1,778.92 + + 4,441.18 +
      + OR + +   + +   + +   + +   + +   + +   + +   + +   + + 67,659 + + 56,772.50 + + 142,277.07 +
      + WA + +   + +   + +   + +   + +   + +   + +   + +   + + 124,366 + + 105,324.31 + + 263,793.22 +
      \ No newline at end of file diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/member-properties-false-false-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/member-properties-false-false-true-result.html index 8b08c59e..24e2316e 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/member-properties-false-false-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/member-properties-false-false-true-result.html @@ -1,458 +1,458 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - All Products -
      - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - All Stores - - 266,773 - - 225,627.23 - - 565,238.13 -
      - All Stores - - Canada - -   - -   - -   -
      - Canada - - BC - -   - -   - -   -
      - BC - - Vancouver - -   - -   - -   -
      - Vancouver - - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - -   - -   - -   -
      - Victoria - -   - -   - -   -
      - Victoria - - Store 20 - - Mid-Size Grocery - - Cobb - - 34452 - - 27463 - - 4193 - - 2795 - - 1 - - 3706 Marvelle Ln - -   - -   - -   -
      - Mexico - -   - -   - -   -
      - USA - - 266,773 - - 225,627.23 - - 565,238.13 -
      - USA - - CA - - 74,748 - - 63,530.43 - - 159,167.84 -
      - CA - - Alameda - -   - -   - -   -
      - Alameda - - HQ - - HeadQuarters - -   - -   - -   - -   - -   - - 0 - - 1 Alameda Way - -   - -   - -   -
      - Beverly Hills - - 21,333 - - 18,266.44 - - 45,750.24 -
      - Beverly Hills - - Store 6 - - Gourmet Supermarket - - Maris - - 23688 - - 15337 - - 5011 - - 3340 - - 1 - - 5495 Mitchell Canyon Road - - 21,333 - - 18,266.44 - - 45,750.24 -
      - Los Angeles - - 25,663 - - 21,771.54 - - 54,545.28 -
      - San Diego - - 25,635 - - 21,713.53 - - 54,431.14 -
      - San Diego - - Store 24 - - Supermarket - - Byrd - -   - -   - -   - -   - - 1 - - 2342 Waltham St. - - 25,635 - - 21,713.53 - - 54,431.14 -
      - San Francisco - - 2,117 - - 1,778.92 - - 4,441.18 -
      - OR - - 67,659 - - 56,772.50 - - 142,277.07 -
      - WA - - 124,366 - - 105,324.31 - - 263,793.22 -
      +   + + All Products +
      + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + All Stores + + 266,773 + + 225,627.23 + + 565,238.13 +
      + All Stores + + Canada + +   + +   + +   +
      + Canada + + BC + +   + +   + +   +
      + BC + + Vancouver + +   + +   + +   +
      + Vancouver + + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + +   + +   + +   +
      + Victoria + +   + +   + +   +
      + Victoria + + Store 20 + + Mid-Size Grocery + + Cobb + + 34452 + + 27463 + + 4193 + + 2795 + + 1 + + 3706 Marvelle Ln + +   + +   + +   +
      + Mexico + +   + +   + +   +
      + USA + + 266,773 + + 225,627.23 + + 565,238.13 +
      + USA + + CA + + 74,748 + + 63,530.43 + + 159,167.84 +
      + CA + + Alameda + +   + +   + +   +
      + Alameda + + HQ + + HeadQuarters + +   + +   + +   + +   + +   + + 0 + + 1 Alameda Way + +   + +   + +   +
      + Beverly Hills + + 21,333 + + 18,266.44 + + 45,750.24 +
      + Beverly Hills + + Store 6 + + Gourmet Supermarket + + Maris + + 23688 + + 15337 + + 5011 + + 3340 + + 1 + + 5495 Mitchell Canyon Road + + 21,333 + + 18,266.44 + + 45,750.24 +
      + Los Angeles + + 25,663 + + 21,771.54 + + 54,545.28 +
      + San Diego + + 25,635 + + 21,713.53 + + 54,431.14 +
      + San Diego + + Store 24 + + Supermarket + + Byrd + +   + +   + +   + +   + + 1 + + 2342 Waltham St. + + 25,635 + + 21,713.53 + + 54,431.14 +
      + San Francisco + + 2,117 + + 1,778.92 + + 4,441.18 +
      + OR + + 67,659 + + 56,772.50 + + 142,277.07 +
      + WA + + 124,366 + + 105,324.31 + + 263,793.22 +
      \ No newline at end of file diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/member-properties-false-true-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/member-properties-false-true-false-result.html index a9baa1a5..06fd1925 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/member-properties-false-true-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/member-properties-false-true-false-result.html @@ -1,828 +1,828 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Product -
      - All Products -
      - Measures -
      - Promotion Media - - Store - - Store Type - - Store Manager - - Store Sqft - - Grocery Sqft - - Frozen Sqft - - Meat Sqft - - Has coffee bar - - Street address - - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - All Stores - -   - -   - -   - -   - -   - -   - -   - -   - - 266,773 - - 225,627.23 - - 565,238.13 -
      - Canada - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   -
      - BC - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   -
      - Vancouver - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   -
      - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - -   - -   - -   -
      - Victoria - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   -
      - Store 20 - - Mid-Size Grocery - - Cobb - - 34452 - - 27463 - - 4193 - - 2795 - - 1 - - 3706 Marvelle Ln - -   - -   - -   -
      - Mexico - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   -
      - USA - -   - -   - -   - -   - -   - -   - -   - -   - - 266,773 - - 225,627.23 - - 565,238.13 -
      - CA - -   - -   - -   - -   - -   - -   - -   - -   - - 74,748 - - 63,530.43 - - 159,167.84 -
      - Alameda - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   -
      - HQ - - HeadQuarters - -   - -   - -   - -   - -   - - 0 - - 1 Alameda Way - -   - -   - -   -
      - Beverly Hills - -   - -   - -   - -   - -   - -   - -   - -   - - 21,333 - - 18,266.44 - - 45,750.24 -
      - Store 6 - - Gourmet Supermarket - - Maris - - 23688 - - 15337 - - 5011 - - 3340 - - 1 - - 5495 Mitchell Canyon Road - - 21,333 - - 18,266.44 - - 45,750.24 -
      - Los Angeles - -   - -   - -   - -   - -   - -   - -   - -   - - 25,663 - - 21,771.54 - - 54,545.28 -
      - San Diego - -   - -   - -   - -   - -   - -   - -   - -   - - 25,635 - - 21,713.53 - - 54,431.14 -
      - Store 24 - - Supermarket - - Byrd - -   - -   - -   - -   - - 1 - - 2342 Waltham St. - - 25,635 - - 21,713.53 - - 54,431.14 -
      - San Francisco - -   - -   - -   - -   - -   - -   - -   - -   - - 2,117 - - 1,778.92 - - 4,441.18 -
      - OR - -   - -   - -   - -   - -   - -   - -   - -   - - 67,659 - - 56,772.50 - - 142,277.07 -
      - WA - -   - -   - -   - -   - -   - -   - -   - -   - - 124,366 - - 105,324.31 - - 263,793.22 -
      +   + + Product +
      + All Products +
      + Measures +
      + Promotion Media + + Store + + Store Type + + Store Manager + + Store Sqft + + Grocery Sqft + + Frozen Sqft + + Meat Sqft + + Has coffee bar + + Street address + + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + All Stores + +   + +   + +   + +   + +   + +   + +   + +   + + 266,773 + + 225,627.23 + + 565,238.13 +
      + Canada + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   +
      + BC + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   +
      + Vancouver + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   +
      + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + +   + +   + +   +
      + Victoria + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   +
      + Store 20 + + Mid-Size Grocery + + Cobb + + 34452 + + 27463 + + 4193 + + 2795 + + 1 + + 3706 Marvelle Ln + +   + +   + +   +
      + Mexico + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   +
      + USA + +   + +   + +   + +   + +   + +   + +   + +   + + 266,773 + + 225,627.23 + + 565,238.13 +
      + CA + +   + +   + +   + +   + +   + +   + +   + +   + + 74,748 + + 63,530.43 + + 159,167.84 +
      + Alameda + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   +
      + HQ + + HeadQuarters + +   + +   + +   + +   + +   + + 0 + + 1 Alameda Way + +   + +   + +   +
      + Beverly Hills + +   + +   + +   + +   + +   + +   + +   + +   + + 21,333 + + 18,266.44 + + 45,750.24 +
      + Store 6 + + Gourmet Supermarket + + Maris + + 23688 + + 15337 + + 5011 + + 3340 + + 1 + + 5495 Mitchell Canyon Road + + 21,333 + + 18,266.44 + + 45,750.24 +
      + Los Angeles + +   + +   + +   + +   + +   + +   + +   + +   + + 25,663 + + 21,771.54 + + 54,545.28 +
      + San Diego + +   + +   + +   + +   + +   + +   + +   + +   + + 25,635 + + 21,713.53 + + 54,431.14 +
      + Store 24 + + Supermarket + + Byrd + +   + +   + +   + +   + + 1 + + 2342 Waltham St. + + 25,635 + + 21,713.53 + + 54,431.14 +
      + San Francisco + +   + +   + +   + +   + +   + +   + +   + +   + + 2,117 + + 1,778.92 + + 4,441.18 +
      + OR + +   + +   + +   + +   + +   + +   + +   + +   + + 67,659 + + 56,772.50 + + 142,277.07 +
      + WA + +   + +   + +   + +   + +   + +   + +   + +   + + 124,366 + + 105,324.31 + + 263,793.22 +
      \ No newline at end of file diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/member-properties-false-true-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/member-properties-false-true-true-result.html index 6786f03e..2afad49f 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/member-properties-false-true-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/member-properties-false-true-true-result.html @@ -1,516 +1,516 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Product -
      - All Products -
      - Promotion Media - - Store - - Measures -
      - (All) - - (All) - - Store Country - - Store State - - Store City - - Store Name - - Store Type - - Store Manager - - Store Sqft - - Grocery Sqft - - Frozen Sqft - - Meat Sqft - - Has coffee bar - - Street address - - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - All Stores - - 266,773 - - 225,627.23 - - 565,238.13 -
      - All Stores - - Canada - -   - -   - -   -
      - Canada - - BC - -   - -   - -   -
      - BC - - Vancouver - -   - -   - -   -
      - Vancouver - - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - -   - -   - -   -
      - Victoria - -   - -   - -   -
      - Victoria - - Store 20 - - Mid-Size Grocery - - Cobb - - 34452 - - 27463 - - 4193 - - 2795 - - 1 - - 3706 Marvelle Ln - -   - -   - -   -
      - Mexico - -   - -   - -   -
      - USA - - 266,773 - - 225,627.23 - - 565,238.13 -
      - USA - - CA - - 74,748 - - 63,530.43 - - 159,167.84 -
      - CA - - Alameda - -   - -   - -   -
      - Alameda - - HQ - - HeadQuarters - -   - -   - -   - -   - -   - - 0 - - 1 Alameda Way - -   - -   - -   -
      - Beverly Hills - - 21,333 - - 18,266.44 - - 45,750.24 -
      - Beverly Hills - - Store 6 - - Gourmet Supermarket - - Maris - - 23688 - - 15337 - - 5011 - - 3340 - - 1 - - 5495 Mitchell Canyon Road - - 21,333 - - 18,266.44 - - 45,750.24 -
      - Los Angeles - - 25,663 - - 21,771.54 - - 54,545.28 -
      - San Diego - - 25,635 - - 21,713.53 - - 54,431.14 -
      - San Diego - - Store 24 - - Supermarket - - Byrd - -   - -   - -   - -   - - 1 - - 2342 Waltham St. - - 25,635 - - 21,713.53 - - 54,431.14 -
      - San Francisco - - 2,117 - - 1,778.92 - - 4,441.18 -
      - OR - - 67,659 - - 56,772.50 - - 142,277.07 -
      - WA - - 124,366 - - 105,324.31 - - 263,793.22 -
      +   + + Product +
      + All Products +
      + Promotion Media + + Store + + Measures +
      + (All) + + (All) + + Store Country + + Store State + + Store City + + Store Name + + Store Type + + Store Manager + + Store Sqft + + Grocery Sqft + + Frozen Sqft + + Meat Sqft + + Has coffee bar + + Street address + + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + All Stores + + 266,773 + + 225,627.23 + + 565,238.13 +
      + All Stores + + Canada + +   + +   + +   +
      + Canada + + BC + +   + +   + +   +
      + BC + + Vancouver + +   + +   + +   +
      + Vancouver + + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + +   + +   + +   +
      + Victoria + +   + +   + +   +
      + Victoria + + Store 20 + + Mid-Size Grocery + + Cobb + + 34452 + + 27463 + + 4193 + + 2795 + + 1 + + 3706 Marvelle Ln + +   + +   + +   +
      + Mexico + +   + +   + +   +
      + USA + + 266,773 + + 225,627.23 + + 565,238.13 +
      + USA + + CA + + 74,748 + + 63,530.43 + + 159,167.84 +
      + CA + + Alameda + +   + +   + +   +
      + Alameda + + HQ + + HeadQuarters + +   + +   + +   + +   + +   + + 0 + + 1 Alameda Way + +   + +   + +   +
      + Beverly Hills + + 21,333 + + 18,266.44 + + 45,750.24 +
      + Beverly Hills + + Store 6 + + Gourmet Supermarket + + Maris + + 23688 + + 15337 + + 5011 + + 3340 + + 1 + + 5495 Mitchell Canyon Road + + 21,333 + + 18,266.44 + + 45,750.24 +
      + Los Angeles + + 25,663 + + 21,771.54 + + 54,545.28 +
      + San Diego + + 25,635 + + 21,713.53 + + 54,431.14 +
      + San Diego + + Store 24 + + Supermarket + + Byrd + +   + +   + +   + +   + + 1 + + 2342 Waltham St. + + 25,635 + + 21,713.53 + + 54,431.14 +
      + San Francisco + + 2,117 + + 1,778.92 + + 4,441.18 +
      + OR + + 67,659 + + 56,772.50 + + 142,277.07 +
      + WA + + 124,366 + + 105,324.31 + + 263,793.22 +
      \ No newline at end of file diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/member-properties-true-false-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/member-properties-true-false-false-result.html index 43be90e7..af83dd64 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/member-properties-true-false-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/member-properties-true-false-false-result.html @@ -1,851 +1,851 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - All Products - - All Products - - All Products -
      - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - All Stores - -   - -   - -   - -   - -   - -   - -   - -   - - 266,773 - - 225,627.23 - - 565,238.13 -
      - All Media - - Canada - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   -
      - All Media - - BC - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   -
      - All Media - - Vancouver - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   -
      - All Media - - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - -   - -   - -   -
      - All Media - - Victoria - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   -
      - All Media - - Store 20 - - Mid-Size Grocery - - Cobb - - 34452 - - 27463 - - 4193 - - 2795 - - 1 - - 3706 Marvelle Ln - -   - -   - -   -
      - All Media - - Mexico - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   -
      - All Media - - USA - -   - -   - -   - -   - -   - -   - -   - -   - - 266,773 - - 225,627.23 - - 565,238.13 -
      - All Media - - CA - -   - -   - -   - -   - -   - -   - -   - -   - - 74,748 - - 63,530.43 - - 159,167.84 -
      - All Media - - Alameda - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   -
      - All Media - - HQ - - HeadQuarters - -   - -   - -   - -   - -   - - 0 - - 1 Alameda Way - -   - -   - -   -
      - All Media - - Beverly Hills - -   - -   - -   - -   - -   - -   - -   - -   - - 21,333 - - 18,266.44 - - 45,750.24 -
      - All Media - - Store 6 - - Gourmet Supermarket - - Maris - - 23688 - - 15337 - - 5011 - - 3340 - - 1 - - 5495 Mitchell Canyon Road - - 21,333 - - 18,266.44 - - 45,750.24 -
      - All Media - - Los Angeles - -   - -   - -   - -   - -   - -   - -   - -   - - 25,663 - - 21,771.54 - - 54,545.28 -
      - All Media - - San Diego - -   - -   - -   - -   - -   - -   - -   - -   - - 25,635 - - 21,713.53 - - 54,431.14 -
      - All Media - - Store 24 - - Supermarket - - Byrd - -   - -   - -   - -   - - 1 - - 2342 Waltham St. - - 25,635 - - 21,713.53 - - 54,431.14 -
      - All Media - - San Francisco - -   - -   - -   - -   - -   - -   - -   - -   - - 2,117 - - 1,778.92 - - 4,441.18 -
      - All Media - - OR - -   - -   - -   - -   - -   - -   - -   - -   - - 67,659 - - 56,772.50 - - 142,277.07 -
      - All Media - - WA - -   - -   - -   - -   - -   - -   - -   - -   - - 124,366 - - 105,324.31 - - 263,793.22 -
      +   + + All Products + + All Products + + All Products +
      + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + All Stores + +   + +   + +   + +   + +   + +   + +   + +   + + 266,773 + + 225,627.23 + + 565,238.13 +
      + All Media + + Canada + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   +
      + All Media + + BC + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   +
      + All Media + + Vancouver + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   +
      + All Media + + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + +   + +   + +   +
      + All Media + + Victoria + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   +
      + All Media + + Store 20 + + Mid-Size Grocery + + Cobb + + 34452 + + 27463 + + 4193 + + 2795 + + 1 + + 3706 Marvelle Ln + +   + +   + +   +
      + All Media + + Mexico + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   +
      + All Media + + USA + +   + +   + +   + +   + +   + +   + +   + +   + + 266,773 + + 225,627.23 + + 565,238.13 +
      + All Media + + CA + +   + +   + +   + +   + +   + +   + +   + +   + + 74,748 + + 63,530.43 + + 159,167.84 +
      + All Media + + Alameda + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   +
      + All Media + + HQ + + HeadQuarters + +   + +   + +   + +   + +   + + 0 + + 1 Alameda Way + +   + +   + +   +
      + All Media + + Beverly Hills + +   + +   + +   + +   + +   + +   + +   + +   + + 21,333 + + 18,266.44 + + 45,750.24 +
      + All Media + + Store 6 + + Gourmet Supermarket + + Maris + + 23688 + + 15337 + + 5011 + + 3340 + + 1 + + 5495 Mitchell Canyon Road + + 21,333 + + 18,266.44 + + 45,750.24 +
      + All Media + + Los Angeles + +   + +   + +   + +   + +   + +   + +   + +   + + 25,663 + + 21,771.54 + + 54,545.28 +
      + All Media + + San Diego + +   + +   + +   + +   + +   + +   + +   + +   + + 25,635 + + 21,713.53 + + 54,431.14 +
      + All Media + + Store 24 + + Supermarket + + Byrd + +   + +   + +   + +   + + 1 + + 2342 Waltham St. + + 25,635 + + 21,713.53 + + 54,431.14 +
      + All Media + + San Francisco + +   + +   + +   + +   + +   + +   + +   + +   + + 2,117 + + 1,778.92 + + 4,441.18 +
      + All Media + + OR + +   + +   + +   + +   + +   + +   + +   + +   + + 67,659 + + 56,772.50 + + 142,277.07 +
      + All Media + + WA + +   + +   + +   + +   + +   + +   + +   + +   + + 124,366 + + 105,324.31 + + 263,793.22 +
      \ No newline at end of file diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/member-properties-true-false-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/member-properties-true-false-true-result.html index 8e00a470..9fcad804 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/member-properties-true-false-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/member-properties-true-false-true-result.html @@ -1,647 +1,647 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - All Products - - All Products - - All Products -
      - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - All Stores - - 266,773 - - 225,627.23 - - 565,238.13 -
      - All Media - - All Stores - - Canada - -   - -   - -   -
      - All Media - - All Stores - - Canada - - BC - -   - -   - -   -
      - All Media - - All Stores - - Canada - - BC - - Vancouver - -   - -   - -   -
      - All Media - - All Stores - - Canada - - BC - - Vancouver - - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - -   - -   - -   -
      - All Media - - All Stores - - Canada - - BC - - Victoria - -   - -   - -   -
      - All Media - - All Stores - - Canada - - BC - - Victoria - - Store 20 - - Mid-Size Grocery - - Cobb - - 34452 - - 27463 - - 4193 - - 2795 - - 1 - - 3706 Marvelle Ln - -   - -   - -   -
      - All Media - - All Stores - - Mexico - -   - -   - -   -
      - All Media - - All Stores - - USA - - 266,773 - - 225,627.23 - - 565,238.13 -
      - All Media - - All Stores - - USA - - CA - - 74,748 - - 63,530.43 - - 159,167.84 -
      - All Media - - All Stores - - USA - - CA - - Alameda - -   - -   - -   -
      - All Media - - All Stores - - USA - - CA - - Alameda - - HQ - - HeadQuarters - -   - -   - -   - -   - -   - - 0 - - 1 Alameda Way - -   - -   - -   -
      - All Media - - All Stores - - USA - - CA - - Beverly Hills - - 21,333 - - 18,266.44 - - 45,750.24 -
      - All Media - - All Stores - - USA - - CA - - Beverly Hills - - Store 6 - - Gourmet Supermarket - - Maris - - 23688 - - 15337 - - 5011 - - 3340 - - 1 - - 5495 Mitchell Canyon Road - - 21,333 - - 18,266.44 - - 45,750.24 -
      - All Media - - All Stores - - USA - - CA - - Los Angeles - - 25,663 - - 21,771.54 - - 54,545.28 -
      - All Media - - All Stores - - USA - - CA - - San Diego - - 25,635 - - 21,713.53 - - 54,431.14 -
      - All Media - - All Stores - - USA - - CA - - San Diego - - Store 24 - - Supermarket - - Byrd - -   - -   - -   - -   - - 1 - - 2342 Waltham St. - - 25,635 - - 21,713.53 - - 54,431.14 -
      - All Media - - All Stores - - USA - - CA - - San Francisco - - 2,117 - - 1,778.92 - - 4,441.18 -
      - All Media - - All Stores - - USA - - OR - - 67,659 - - 56,772.50 - - 142,277.07 -
      - All Media - - All Stores - - USA - - WA - - 124,366 - - 105,324.31 - - 263,793.22 -
      +   + + All Products + + All Products + + All Products +
      + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + All Stores + + 266,773 + + 225,627.23 + + 565,238.13 +
      + All Media + + All Stores + + Canada + +   + +   + +   +
      + All Media + + All Stores + + Canada + + BC + +   + +   + +   +
      + All Media + + All Stores + + Canada + + BC + + Vancouver + +   + +   + +   +
      + All Media + + All Stores + + Canada + + BC + + Vancouver + + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + +   + +   + +   +
      + All Media + + All Stores + + Canada + + BC + + Victoria + +   + +   + +   +
      + All Media + + All Stores + + Canada + + BC + + Victoria + + Store 20 + + Mid-Size Grocery + + Cobb + + 34452 + + 27463 + + 4193 + + 2795 + + 1 + + 3706 Marvelle Ln + +   + +   + +   +
      + All Media + + All Stores + + Mexico + +   + +   + +   +
      + All Media + + All Stores + + USA + + 266,773 + + 225,627.23 + + 565,238.13 +
      + All Media + + All Stores + + USA + + CA + + 74,748 + + 63,530.43 + + 159,167.84 +
      + All Media + + All Stores + + USA + + CA + + Alameda + +   + +   + +   +
      + All Media + + All Stores + + USA + + CA + + Alameda + + HQ + + HeadQuarters + +   + +   + +   + +   + +   + + 0 + + 1 Alameda Way + +   + +   + +   +
      + All Media + + All Stores + + USA + + CA + + Beverly Hills + + 21,333 + + 18,266.44 + + 45,750.24 +
      + All Media + + All Stores + + USA + + CA + + Beverly Hills + + Store 6 + + Gourmet Supermarket + + Maris + + 23688 + + 15337 + + 5011 + + 3340 + + 1 + + 5495 Mitchell Canyon Road + + 21,333 + + 18,266.44 + + 45,750.24 +
      + All Media + + All Stores + + USA + + CA + + Los Angeles + + 25,663 + + 21,771.54 + + 54,545.28 +
      + All Media + + All Stores + + USA + + CA + + San Diego + + 25,635 + + 21,713.53 + + 54,431.14 +
      + All Media + + All Stores + + USA + + CA + + San Diego + + Store 24 + + Supermarket + + Byrd + +   + +   + +   + +   + + 1 + + 2342 Waltham St. + + 25,635 + + 21,713.53 + + 54,431.14 +
      + All Media + + All Stores + + USA + + CA + + San Francisco + + 2,117 + + 1,778.92 + + 4,441.18 +
      + All Media + + All Stores + + USA + + OR + + 67,659 + + 56,772.50 + + 142,277.07 +
      + All Media + + All Stores + + USA + + WA + + 124,366 + + 105,324.31 + + 263,793.22 +
      \ No newline at end of file diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/member-properties-true-true-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/member-properties-true-true-false-result.html index f22e1771..bdbfac4e 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/member-properties-true-true-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/member-properties-true-true-false-result.html @@ -1,903 +1,903 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Product - - Product - - Product -
      - All Products - - All Products - - All Products -
      - Measures - - Measures - - Measures -
      - Promotion Media - - Store - - Store Type - - Store Manager - - Store Sqft - - Grocery Sqft - - Frozen Sqft - - Meat Sqft - - Has coffee bar - - Street address - - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - All Stores - -   - -   - -   - -   - -   - -   - -   - -   - - 266,773 - - 225,627.23 - - 565,238.13 -
      - All Media - - Canada - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   -
      - All Media - - BC - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   -
      - All Media - - Vancouver - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   -
      - All Media - - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - -   - -   - -   -
      - All Media - - Victoria - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   -
      - All Media - - Store 20 - - Mid-Size Grocery - - Cobb - - 34452 - - 27463 - - 4193 - - 2795 - - 1 - - 3706 Marvelle Ln - -   - -   - -   -
      - All Media - - Mexico - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   -
      - All Media - - USA - -   - -   - -   - -   - -   - -   - -   - -   - - 266,773 - - 225,627.23 - - 565,238.13 -
      - All Media - - CA - -   - -   - -   - -   - -   - -   - -   - -   - - 74,748 - - 63,530.43 - - 159,167.84 -
      - All Media - - Alameda - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   - -   -
      - All Media - - HQ - - HeadQuarters - -   - -   - -   - -   - -   - - 0 - - 1 Alameda Way - -   - -   - -   -
      - All Media - - Beverly Hills - -   - -   - -   - -   - -   - -   - -   - -   - - 21,333 - - 18,266.44 - - 45,750.24 -
      - All Media - - Store 6 - - Gourmet Supermarket - - Maris - - 23688 - - 15337 - - 5011 - - 3340 - - 1 - - 5495 Mitchell Canyon Road - - 21,333 - - 18,266.44 - - 45,750.24 -
      - All Media - - Los Angeles - -   - -   - -   - -   - -   - -   - -   - -   - - 25,663 - - 21,771.54 - - 54,545.28 -
      - All Media - - San Diego - -   - -   - -   - -   - -   - -   - -   - -   - - 25,635 - - 21,713.53 - - 54,431.14 -
      - All Media - - Store 24 - - Supermarket - - Byrd - -   - -   - -   - -   - - 1 - - 2342 Waltham St. - - 25,635 - - 21,713.53 - - 54,431.14 -
      - All Media - - San Francisco - -   - -   - -   - -   - -   - -   - -   - -   - - 2,117 - - 1,778.92 - - 4,441.18 -
      - All Media - - OR - -   - -   - -   - -   - -   - -   - -   - -   - - 67,659 - - 56,772.50 - - 142,277.07 -
      - All Media - - WA - -   - -   - -   - -   - -   - -   - -   - -   - - 124,366 - - 105,324.31 - - 263,793.22 -
      +   + + Product + + Product + + Product +
      + All Products + + All Products + + All Products +
      + Measures + + Measures + + Measures +
      + Promotion Media + + Store + + Store Type + + Store Manager + + Store Sqft + + Grocery Sqft + + Frozen Sqft + + Meat Sqft + + Has coffee bar + + Street address + + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + All Stores + +   + +   + +   + +   + +   + +   + +   + +   + + 266,773 + + 225,627.23 + + 565,238.13 +
      + All Media + + Canada + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   +
      + All Media + + BC + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   +
      + All Media + + Vancouver + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   +
      + All Media + + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + +   + +   + +   +
      + All Media + + Victoria + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   +
      + All Media + + Store 20 + + Mid-Size Grocery + + Cobb + + 34452 + + 27463 + + 4193 + + 2795 + + 1 + + 3706 Marvelle Ln + +   + +   + +   +
      + All Media + + Mexico + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   +
      + All Media + + USA + +   + +   + +   + +   + +   + +   + +   + +   + + 266,773 + + 225,627.23 + + 565,238.13 +
      + All Media + + CA + +   + +   + +   + +   + +   + +   + +   + +   + + 74,748 + + 63,530.43 + + 159,167.84 +
      + All Media + + Alameda + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   + +   +
      + All Media + + HQ + + HeadQuarters + +   + +   + +   + +   + +   + + 0 + + 1 Alameda Way + +   + +   + +   +
      + All Media + + Beverly Hills + +   + +   + +   + +   + +   + +   + +   + +   + + 21,333 + + 18,266.44 + + 45,750.24 +
      + All Media + + Store 6 + + Gourmet Supermarket + + Maris + + 23688 + + 15337 + + 5011 + + 3340 + + 1 + + 5495 Mitchell Canyon Road + + 21,333 + + 18,266.44 + + 45,750.24 +
      + All Media + + Los Angeles + +   + +   + +   + +   + +   + +   + +   + +   + + 25,663 + + 21,771.54 + + 54,545.28 +
      + All Media + + San Diego + +   + +   + +   + +   + +   + +   + +   + +   + + 25,635 + + 21,713.53 + + 54,431.14 +
      + All Media + + Store 24 + + Supermarket + + Byrd + +   + +   + +   + +   + + 1 + + 2342 Waltham St. + + 25,635 + + 21,713.53 + + 54,431.14 +
      + All Media + + San Francisco + +   + +   + +   + +   + +   + +   + +   + +   + + 2,117 + + 1,778.92 + + 4,441.18 +
      + All Media + + OR + +   + +   + +   + +   + +   + +   + +   + +   + + 67,659 + + 56,772.50 + + 142,277.07 +
      + All Media + + WA + +   + +   + +   + +   + +   + +   + +   + +   + + 124,366 + + 105,324.31 + + 263,793.22 +
      \ No newline at end of file diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/member-properties-true-true-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/member-properties-true-true-true-result.html index ecb7aa95..97512a8b 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/member-properties-true-true-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/member-properties-true-true-true-result.html @@ -1,717 +1,717 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Product - - Product - - Product -
      - All Products - - All Products - - All Products -
      - Promotion Media - - Store - - Measures - - Measures - - Measures -
      - (All) - - (All) - - Store Country - - Store State - - Store City - - Store Name - - Store Type - - Store Manager - - Store Sqft - - Grocery Sqft - - Frozen Sqft - - Meat Sqft - - Has coffee bar - - Street address - - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - All Stores - - 266,773 - - 225,627.23 - - 565,238.13 -
      - All Media - - All Stores - - Canada - -   - -   - -   -
      - All Media - - All Stores - - Canada - - BC - -   - -   - -   -
      - All Media - - All Stores - - Canada - - BC - - Vancouver - -   - -   - -   -
      - All Media - - All Stores - - Canada - - BC - - Vancouver - - Store 19 - - Deluxe Supermarket - - Ruth - - 23112 - - 16418 - - 4016 - - 2678 - - 1 - - 6644 Sudance Drive - -   - -   - -   -
      - All Media - - All Stores - - Canada - - BC - - Victoria - -   - -   - -   -
      - All Media - - All Stores - - Canada - - BC - - Victoria - - Store 20 - - Mid-Size Grocery - - Cobb - - 34452 - - 27463 - - 4193 - - 2795 - - 1 - - 3706 Marvelle Ln - -   - -   - -   -
      - All Media - - All Stores - - Mexico - -   - -   - -   -
      - All Media - - All Stores - - USA - - 266,773 - - 225,627.23 - - 565,238.13 -
      - All Media - - All Stores - - USA - - CA - - 74,748 - - 63,530.43 - - 159,167.84 -
      - All Media - - All Stores - - USA - - CA - - Alameda - -   - -   - -   -
      - All Media - - All Stores - - USA - - CA - - Alameda - - HQ - - HeadQuarters - -   - -   - -   - -   - -   - - 0 - - 1 Alameda Way - -   - -   - -   -
      - All Media - - All Stores - - USA - - CA - - Beverly Hills - - 21,333 - - 18,266.44 - - 45,750.24 -
      - All Media - - All Stores - - USA - - CA - - Beverly Hills - - Store 6 - - Gourmet Supermarket - - Maris - - 23688 - - 15337 - - 5011 - - 3340 - - 1 - - 5495 Mitchell Canyon Road - - 21,333 - - 18,266.44 - - 45,750.24 -
      - All Media - - All Stores - - USA - - CA - - Los Angeles - - 25,663 - - 21,771.54 - - 54,545.28 -
      - All Media - - All Stores - - USA - - CA - - San Diego - - 25,635 - - 21,713.53 - - 54,431.14 -
      - All Media - - All Stores - - USA - - CA - - San Diego - - Store 24 - - Supermarket - - Byrd - -   - -   - -   - -   - - 1 - - 2342 Waltham St. - - 25,635 - - 21,713.53 - - 54,431.14 -
      - All Media - - All Stores - - USA - - CA - - San Francisco - - 2,117 - - 1,778.92 - - 4,441.18 -
      - All Media - - All Stores - - USA - - OR - - 67,659 - - 56,772.50 - - 142,277.07 -
      - All Media - - All Stores - - USA - - WA - - 124,366 - - 105,324.31 - - 263,793.22 -
      +   + + Product + + Product + + Product +
      + All Products + + All Products + + All Products +
      + Promotion Media + + Store + + Measures + + Measures + + Measures +
      + (All) + + (All) + + Store Country + + Store State + + Store City + + Store Name + + Store Type + + Store Manager + + Store Sqft + + Grocery Sqft + + Frozen Sqft + + Meat Sqft + + Has coffee bar + + Street address + + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + All Stores + + 266,773 + + 225,627.23 + + 565,238.13 +
      + All Media + + All Stores + + Canada + +   + +   + +   +
      + All Media + + All Stores + + Canada + + BC + +   + +   + +   +
      + All Media + + All Stores + + Canada + + BC + + Vancouver + +   + +   + +   +
      + All Media + + All Stores + + Canada + + BC + + Vancouver + + Store 19 + + Deluxe Supermarket + + Ruth + + 23112 + + 16418 + + 4016 + + 2678 + + 1 + + 6644 Sudance Drive + +   + +   + +   +
      + All Media + + All Stores + + Canada + + BC + + Victoria + +   + +   + +   +
      + All Media + + All Stores + + Canada + + BC + + Victoria + + Store 20 + + Mid-Size Grocery + + Cobb + + 34452 + + 27463 + + 4193 + + 2795 + + 1 + + 3706 Marvelle Ln + +   + +   + +   +
      + All Media + + All Stores + + Mexico + +   + +   + +   +
      + All Media + + All Stores + + USA + + 266,773 + + 225,627.23 + + 565,238.13 +
      + All Media + + All Stores + + USA + + CA + + 74,748 + + 63,530.43 + + 159,167.84 +
      + All Media + + All Stores + + USA + + CA + + Alameda + +   + +   + +   +
      + All Media + + All Stores + + USA + + CA + + Alameda + + HQ + + HeadQuarters + +   + +   + +   + +   + +   + + 0 + + 1 Alameda Way + +   + +   + +   +
      + All Media + + All Stores + + USA + + CA + + Beverly Hills + + 21,333 + + 18,266.44 + + 45,750.24 +
      + All Media + + All Stores + + USA + + CA + + Beverly Hills + + Store 6 + + Gourmet Supermarket + + Maris + + 23688 + + 15337 + + 5011 + + 3340 + + 1 + + 5495 Mitchell Canyon Road + + 21,333 + + 18,266.44 + + 45,750.24 +
      + All Media + + All Stores + + USA + + CA + + Los Angeles + + 25,663 + + 21,771.54 + + 54,545.28 +
      + All Media + + All Stores + + USA + + CA + + San Diego + + 25,635 + + 21,713.53 + + 54,431.14 +
      + All Media + + All Stores + + USA + + CA + + San Diego + + Store 24 + + Supermarket + + Byrd + +   + +   + +   + +   + + 1 + + 2342 Waltham St. + + 25,635 + + 21,713.53 + + 54,431.14 +
      + All Media + + All Stores + + USA + + CA + + San Francisco + + 2,117 + + 1,778.92 + + 4,441.18 +
      + All Media + + All Stores + + USA + + OR + + 67,659 + + 56,772.50 + + 142,277.07 +
      + All Media + + All Stores + + USA + + WA + + 124,366 + + 105,324.31 + + 263,793.22 +
      \ No newline at end of file diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/more-complex-columns-false-false-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/more-complex-columns-false-false-false-result.html index 1b577133..94bb0d66 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/more-complex-columns-false-false-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/more-complex-columns-false-false-false-result.html @@ -1,428 +1,428 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - All Gender - - F - - M -
      - All Products - - Drink - - Alcoholic Beverages - - Beer and Wine - - Beer - - Good - - Good Imported Beer - - Good Light Beer - - Pearl - - Portsmouth - - Top Measure - - Walrus - - Wine - - Beverages - - Dairy - - Food - - Non-Consumable - - All Products - - All Products -
      - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - 266,773 - - 225,627.23 - - 565,238.13 - - 24,597 - - 19,477.23 - - 48,836.21 - - 6,838 - - 5,576.79 - - 14,029.08 - - 6,838 - - 5,576.79 - - 14,029.08 - - 1,683 - - 1,348.14 - - 3,400.45 - - 269 - - 198.21 - - 500.18 - - 154 - - 98.17 - - 249.48 - - 115 - - 100.04 - - 250.70 - - 385 - - 218.30 - - 549.85 - - 362 - - 412.24 - - 1,067.17 - - 306 - - 141.94 - - 343.04 - - 361 - - 377.45 - - 940.21 - - 5,155 - - 4,228.64 - - 10,628.63 - - 13,573 - - 11,069.53 - - 27,748.53 - - 4,186 - - 2,830.92 - - 7,058.60 - - 191,940 - - 163,270.72 - - 409,035.59 - - 50,236 - - 42,879.28 - - 107,366.33 - - 131,558 - - 111,777.48 - - 280,226.21 - - 135,215 - - 113,849.75 - - 285,011.92 -
      +   + + All Gender + + F + + M +
      + All Products + + Drink + + Alcoholic Beverages + + Beer and Wine + + Beer + + Good + + Good Imported Beer + + Good Light Beer + + Pearl + + Portsmouth + + Top Measure + + Walrus + + Wine + + Beverages + + Dairy + + Food + + Non-Consumable + + All Products + + All Products +
      + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + 266,773 + + 225,627.23 + + 565,238.13 + + 24,597 + + 19,477.23 + + 48,836.21 + + 6,838 + + 5,576.79 + + 14,029.08 + + 6,838 + + 5,576.79 + + 14,029.08 + + 1,683 + + 1,348.14 + + 3,400.45 + + 269 + + 198.21 + + 500.18 + + 154 + + 98.17 + + 249.48 + + 115 + + 100.04 + + 250.70 + + 385 + + 218.30 + + 549.85 + + 362 + + 412.24 + + 1,067.17 + + 306 + + 141.94 + + 343.04 + + 361 + + 377.45 + + 940.21 + + 5,155 + + 4,228.64 + + 10,628.63 + + 13,573 + + 11,069.53 + + 27,748.53 + + 4,186 + + 2,830.92 + + 7,058.60 + + 191,940 + + 163,270.72 + + 409,035.59 + + 50,236 + + 42,879.28 + + 107,366.33 + + 131,558 + + 111,777.48 + + 280,226.21 + + 135,215 + + 113,849.75 + + 285,011.92 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/more-complex-columns-false-false-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/more-complex-columns-false-false-true-result.html index 4863442c..eb43aaef 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/more-complex-columns-false-false-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/more-complex-columns-false-false-true-result.html @@ -1,463 +1,463 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - All Gender - - All Gender -
      - F - - M -
      - All Products - - All Products - - All Products - - All Products -
      - Drink - - Drink - - Food - - Non-Consumable -
      - Alcoholic Beverages - - Alcoholic Beverages - - Beverages - - Dairy -
      - Beer and Wine - - Beer and Wine -
      - Beer - - Beer - - Wine -
      - Good - - Good - - Pearl - - Portsmouth - - Top Measure - - Walrus -
      - Good Imported Beer - - Good Light Beer -
      - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - 266,773 - - 225,627.23 - - 565,238.13 - - 24,597 - - 19,477.23 - - 48,836.21 - - 6,838 - - 5,576.79 - - 14,029.08 - - 6,838 - - 5,576.79 - - 14,029.08 - - 1,683 - - 1,348.14 - - 3,400.45 - - 269 - - 198.21 - - 500.18 - - 154 - - 98.17 - - 249.48 - - 115 - - 100.04 - - 250.70 - - 385 - - 218.30 - - 549.85 - - 362 - - 412.24 - - 1,067.17 - - 306 - - 141.94 - - 343.04 - - 361 - - 377.45 - - 940.21 - - 5,155 - - 4,228.64 - - 10,628.63 - - 13,573 - - 11,069.53 - - 27,748.53 - - 4,186 - - 2,830.92 - - 7,058.60 - - 191,940 - - 163,270.72 - - 409,035.59 - - 50,236 - - 42,879.28 - - 107,366.33 - - 131,558 - - 111,777.48 - - 280,226.21 - - 135,215 - - 113,849.75 - - 285,011.92 -
      +   + + All Gender + + All Gender +
      + F + + M +
      + All Products + + All Products + + All Products + + All Products +
      + Drink + + Drink + + Food + + Non-Consumable +
      + Alcoholic Beverages + + Alcoholic Beverages + + Beverages + + Dairy +
      + Beer and Wine + + Beer and Wine +
      + Beer + + Beer + + Wine +
      + Good + + Good + + Pearl + + Portsmouth + + Top Measure + + Walrus +
      + Good Imported Beer + + Good Light Beer +
      + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + 266,773 + + 225,627.23 + + 565,238.13 + + 24,597 + + 19,477.23 + + 48,836.21 + + 6,838 + + 5,576.79 + + 14,029.08 + + 6,838 + + 5,576.79 + + 14,029.08 + + 1,683 + + 1,348.14 + + 3,400.45 + + 269 + + 198.21 + + 500.18 + + 154 + + 98.17 + + 249.48 + + 115 + + 100.04 + + 250.70 + + 385 + + 218.30 + + 549.85 + + 362 + + 412.24 + + 1,067.17 + + 306 + + 141.94 + + 343.04 + + 361 + + 377.45 + + 940.21 + + 5,155 + + 4,228.64 + + 10,628.63 + + 13,573 + + 11,069.53 + + 27,748.53 + + 4,186 + + 2,830.92 + + 7,058.60 + + 191,940 + + 163,270.72 + + 409,035.59 + + 50,236 + + 42,879.28 + + 107,366.33 + + 131,558 + + 111,777.48 + + 280,226.21 + + 135,215 + + 113,849.75 + + 285,011.92 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/more-complex-columns-false-true-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/more-complex-columns-false-true-false-result.html index de4d9887..119eb011 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/more-complex-columns-false-true-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/more-complex-columns-false-true-false-result.html @@ -1,506 +1,506 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Gender -
      - All Gender - - F - - M -
      - Product - - Product - - Product -
      - All Products - - Drink - - Alcoholic Beverages - - Beer and Wine - - Beer - - Good - - Good Imported Beer - - Good Light Beer - - Pearl - - Portsmouth - - Top Measure - - Walrus - - Wine - - Beverages - - Dairy - - Food - - Non-Consumable - - All Products - - All Products -
      - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures -
      - Promotion Media - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - 266,773 - - 225,627.23 - - 565,238.13 - - 24,597 - - 19,477.23 - - 48,836.21 - - 6,838 - - 5,576.79 - - 14,029.08 - - 6,838 - - 5,576.79 - - 14,029.08 - - 1,683 - - 1,348.14 - - 3,400.45 - - 269 - - 198.21 - - 500.18 - - 154 - - 98.17 - - 249.48 - - 115 - - 100.04 - - 250.70 - - 385 - - 218.30 - - 549.85 - - 362 - - 412.24 - - 1,067.17 - - 306 - - 141.94 - - 343.04 - - 361 - - 377.45 - - 940.21 - - 5,155 - - 4,228.64 - - 10,628.63 - - 13,573 - - 11,069.53 - - 27,748.53 - - 4,186 - - 2,830.92 - - 7,058.60 - - 191,940 - - 163,270.72 - - 409,035.59 - - 50,236 - - 42,879.28 - - 107,366.33 - - 131,558 - - 111,777.48 - - 280,226.21 - - 135,215 - - 113,849.75 - - 285,011.92 -
      +   + + Gender +
      + All Gender + + F + + M +
      + Product + + Product + + Product +
      + All Products + + Drink + + Alcoholic Beverages + + Beer and Wine + + Beer + + Good + + Good Imported Beer + + Good Light Beer + + Pearl + + Portsmouth + + Top Measure + + Walrus + + Wine + + Beverages + + Dairy + + Food + + Non-Consumable + + All Products + + All Products +
      + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures +
      + Promotion Media + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + 266,773 + + 225,627.23 + + 565,238.13 + + 24,597 + + 19,477.23 + + 48,836.21 + + 6,838 + + 5,576.79 + + 14,029.08 + + 6,838 + + 5,576.79 + + 14,029.08 + + 1,683 + + 1,348.14 + + 3,400.45 + + 269 + + 198.21 + + 500.18 + + 154 + + 98.17 + + 249.48 + + 115 + + 100.04 + + 250.70 + + 385 + + 218.30 + + 549.85 + + 362 + + 412.24 + + 1,067.17 + + 306 + + 141.94 + + 343.04 + + 361 + + 377.45 + + 940.21 + + 5,155 + + 4,228.64 + + 10,628.63 + + 13,573 + + 11,069.53 + + 27,748.53 + + 4,186 + + 2,830.92 + + 7,058.60 + + 191,940 + + 163,270.72 + + 409,035.59 + + 50,236 + + 42,879.28 + + 107,366.33 + + 131,558 + + 111,777.48 + + 280,226.21 + + 135,215 + + 113,849.75 + + 285,011.92 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/more-complex-columns-false-true-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/more-complex-columns-false-true-true-result.html index b06744bc..0568f7bf 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/more-complex-columns-false-true-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/more-complex-columns-false-true-true-result.html @@ -1,544 +1,544 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Gender -
      - All Gender - - All Gender -
      - F - - M -
      - Product - - Product - - Product -
      - All Products - - All Products - - All Products - - All Products -
      - Drink - - Drink - - Food - - Non-Consumable -
      - Alcoholic Beverages - - Alcoholic Beverages - - Beverages - - Dairy -
      - Beer and Wine - - Beer and Wine -
      - Beer - - Beer - - Wine -
      - Good - - Good - - Pearl - - Portsmouth - - Top Measure - - Walrus -
      - Good Imported Beer - - Good Light Beer -
      - Promotion Media - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures -
      - (All) - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - 266,773 - - 225,627.23 - - 565,238.13 - - 24,597 - - 19,477.23 - - 48,836.21 - - 6,838 - - 5,576.79 - - 14,029.08 - - 6,838 - - 5,576.79 - - 14,029.08 - - 1,683 - - 1,348.14 - - 3,400.45 - - 269 - - 198.21 - - 500.18 - - 154 - - 98.17 - - 249.48 - - 115 - - 100.04 - - 250.70 - - 385 - - 218.30 - - 549.85 - - 362 - - 412.24 - - 1,067.17 - - 306 - - 141.94 - - 343.04 - - 361 - - 377.45 - - 940.21 - - 5,155 - - 4,228.64 - - 10,628.63 - - 13,573 - - 11,069.53 - - 27,748.53 - - 4,186 - - 2,830.92 - - 7,058.60 - - 191,940 - - 163,270.72 - - 409,035.59 - - 50,236 - - 42,879.28 - - 107,366.33 - - 131,558 - - 111,777.48 - - 280,226.21 - - 135,215 - - 113,849.75 - - 285,011.92 -
      +   + + Gender +
      + All Gender + + All Gender +
      + F + + M +
      + Product + + Product + + Product +
      + All Products + + All Products + + All Products + + All Products +
      + Drink + + Drink + + Food + + Non-Consumable +
      + Alcoholic Beverages + + Alcoholic Beverages + + Beverages + + Dairy +
      + Beer and Wine + + Beer and Wine +
      + Beer + + Beer + + Wine +
      + Good + + Good + + Pearl + + Portsmouth + + Top Measure + + Walrus +
      + Good Imported Beer + + Good Light Beer +
      + Promotion Media + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures +
      + (All) + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + 266,773 + + 225,627.23 + + 565,238.13 + + 24,597 + + 19,477.23 + + 48,836.21 + + 6,838 + + 5,576.79 + + 14,029.08 + + 6,838 + + 5,576.79 + + 14,029.08 + + 1,683 + + 1,348.14 + + 3,400.45 + + 269 + + 198.21 + + 500.18 + + 154 + + 98.17 + + 249.48 + + 115 + + 100.04 + + 250.70 + + 385 + + 218.30 + + 549.85 + + 362 + + 412.24 + + 1,067.17 + + 306 + + 141.94 + + 343.04 + + 361 + + 377.45 + + 940.21 + + 5,155 + + 4,228.64 + + 10,628.63 + + 13,573 + + 11,069.53 + + 27,748.53 + + 4,186 + + 2,830.92 + + 7,058.60 + + 191,940 + + 163,270.72 + + 409,035.59 + + 50,236 + + 42,879.28 + + 107,366.33 + + 131,558 + + 111,777.48 + + 280,226.21 + + 135,215 + + 113,849.75 + + 285,011.92 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/more-complex-columns-true-false-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/more-complex-columns-true-false-false-result.html index de888ab8..67fa5314 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/more-complex-columns-true-false-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/more-complex-columns-true-false-false-result.html @@ -1,704 +1,704 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - F - - F - - F - - M - - M - - M -
      - All Products - - All Products - - All Products - - Drink - - Drink - - Drink - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer - - Beer - - Beer - - Good - - Good - - Good - - Good Imported Beer - - Good Imported Beer - - Good Imported Beer - - Good Light Beer - - Good Light Beer - - Good Light Beer - - Pearl - - Pearl - - Pearl - - Portsmouth - - Portsmouth - - Portsmouth - - Top Measure - - Top Measure - - Top Measure - - Walrus - - Walrus - - Walrus - - Wine - - Wine - - Wine - - Beverages - - Beverages - - Beverages - - Dairy - - Dairy - - Dairy - - Food - - Food - - Food - - Non-Consumable - - Non-Consumable - - Non-Consumable - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products -
      - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - 266,773 - - 225,627.23 - - 565,238.13 - - 24,597 - - 19,477.23 - - 48,836.21 - - 6,838 - - 5,576.79 - - 14,029.08 - - 6,838 - - 5,576.79 - - 14,029.08 - - 1,683 - - 1,348.14 - - 3,400.45 - - 269 - - 198.21 - - 500.18 - - 154 - - 98.17 - - 249.48 - - 115 - - 100.04 - - 250.70 - - 385 - - 218.30 - - 549.85 - - 362 - - 412.24 - - 1,067.17 - - 306 - - 141.94 - - 343.04 - - 361 - - 377.45 - - 940.21 - - 5,155 - - 4,228.64 - - 10,628.63 - - 13,573 - - 11,069.53 - - 27,748.53 - - 4,186 - - 2,830.92 - - 7,058.60 - - 191,940 - - 163,270.72 - - 409,035.59 - - 50,236 - - 42,879.28 - - 107,366.33 - - 131,558 - - 111,777.48 - - 280,226.21 - - 135,215 - - 113,849.75 - - 285,011.92 -
      +   + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + F + + F + + F + + M + + M + + M +
      + All Products + + All Products + + All Products + + Drink + + Drink + + Drink + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer + + Beer + + Beer + + Good + + Good + + Good + + Good Imported Beer + + Good Imported Beer + + Good Imported Beer + + Good Light Beer + + Good Light Beer + + Good Light Beer + + Pearl + + Pearl + + Pearl + + Portsmouth + + Portsmouth + + Portsmouth + + Top Measure + + Top Measure + + Top Measure + + Walrus + + Walrus + + Walrus + + Wine + + Wine + + Wine + + Beverages + + Beverages + + Beverages + + Dairy + + Dairy + + Dairy + + Food + + Food + + Food + + Non-Consumable + + Non-Consumable + + Non-Consumable + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products +
      + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + 266,773 + + 225,627.23 + + 565,238.13 + + 24,597 + + 19,477.23 + + 48,836.21 + + 6,838 + + 5,576.79 + + 14,029.08 + + 6,838 + + 5,576.79 + + 14,029.08 + + 1,683 + + 1,348.14 + + 3,400.45 + + 269 + + 198.21 + + 500.18 + + 154 + + 98.17 + + 249.48 + + 115 + + 100.04 + + 250.70 + + 385 + + 218.30 + + 549.85 + + 362 + + 412.24 + + 1,067.17 + + 306 + + 141.94 + + 343.04 + + 361 + + 377.45 + + 940.21 + + 5,155 + + 4,228.64 + + 10,628.63 + + 13,573 + + 11,069.53 + + 27,748.53 + + 4,186 + + 2,830.92 + + 7,058.60 + + 191,940 + + 163,270.72 + + 409,035.59 + + 50,236 + + 42,879.28 + + 107,366.33 + + 131,558 + + 111,777.48 + + 280,226.21 + + 135,215 + + 113,849.75 + + 285,011.92 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/more-complex-columns-true-false-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/more-complex-columns-true-false-true-result.html index ec5e8295..7e90e76a 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/more-complex-columns-true-false-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/more-complex-columns-true-false-true-result.html @@ -1,1249 +1,1249 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender -
      - F - - F - - F - - M - - M - - M -
      - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products -
      - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Food - - Food - - Food - - Non-Consumable - - Non-Consumable - - Non-Consumable -
      - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Beverages - - Beverages - - Beverages - - Dairy - - Dairy - - Dairy -
      - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine -
      - Beer - - Beer - - Beer - - Beer - - Beer - - Beer - - Beer - - Beer - - Beer - - Beer - - Beer - - Beer - - Beer - - Beer - - Beer - - Beer - - Beer - - Beer - - Beer - - Beer - - Beer - - Beer - - Beer - - Beer - - Wine - - Wine - - Wine -
      - Good - - Good - - Good - - Good - - Good - - Good - - Good - - Good - - Good - - Pearl - - Pearl - - Pearl - - Portsmouth - - Portsmouth - - Portsmouth - - Top Measure - - Top Measure - - Top Measure - - Walrus - - Walrus - - Walrus -
      - Good Imported Beer - - Good Imported Beer - - Good Imported Beer - - Good Light Beer - - Good Light Beer - - Good Light Beer -
      - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - 266,773 - - 225,627.23 - - 565,238.13 - - 24,597 - - 19,477.23 - - 48,836.21 - - 6,838 - - 5,576.79 - - 14,029.08 - - 6,838 - - 5,576.79 - - 14,029.08 - - 1,683 - - 1,348.14 - - 3,400.45 - - 269 - - 198.21 - - 500.18 - - 154 - - 98.17 - - 249.48 - - 115 - - 100.04 - - 250.70 - - 385 - - 218.30 - - 549.85 - - 362 - - 412.24 - - 1,067.17 - - 306 - - 141.94 - - 343.04 - - 361 - - 377.45 - - 940.21 - - 5,155 - - 4,228.64 - - 10,628.63 - - 13,573 - - 11,069.53 - - 27,748.53 - - 4,186 - - 2,830.92 - - 7,058.60 - - 191,940 - - 163,270.72 - - 409,035.59 - - 50,236 - - 42,879.28 - - 107,366.33 - - 131,558 - - 111,777.48 - - 280,226.21 - - 135,215 - - 113,849.75 - - 285,011.92 -
      +   + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender +
      + F + + F + + F + + M + + M + + M +
      + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products +
      + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Food + + Food + + Food + + Non-Consumable + + Non-Consumable + + Non-Consumable +
      + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Beverages + + Beverages + + Beverages + + Dairy + + Dairy + + Dairy +
      + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine +
      + Beer + + Beer + + Beer + + Beer + + Beer + + Beer + + Beer + + Beer + + Beer + + Beer + + Beer + + Beer + + Beer + + Beer + + Beer + + Beer + + Beer + + Beer + + Beer + + Beer + + Beer + + Beer + + Beer + + Beer + + Wine + + Wine + + Wine +
      + Good + + Good + + Good + + Good + + Good + + Good + + Good + + Good + + Good + + Pearl + + Pearl + + Pearl + + Portsmouth + + Portsmouth + + Portsmouth + + Top Measure + + Top Measure + + Top Measure + + Walrus + + Walrus + + Walrus +
      + Good Imported Beer + + Good Imported Beer + + Good Imported Beer + + Good Light Beer + + Good Light Beer + + Good Light Beer +
      + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + 266,773 + + 225,627.23 + + 565,238.13 + + 24,597 + + 19,477.23 + + 48,836.21 + + 6,838 + + 5,576.79 + + 14,029.08 + + 6,838 + + 5,576.79 + + 14,029.08 + + 1,683 + + 1,348.14 + + 3,400.45 + + 269 + + 198.21 + + 500.18 + + 154 + + 98.17 + + 249.48 + + 115 + + 100.04 + + 250.70 + + 385 + + 218.30 + + 549.85 + + 362 + + 412.24 + + 1,067.17 + + 306 + + 141.94 + + 343.04 + + 361 + + 377.45 + + 940.21 + + 5,155 + + 4,228.64 + + 10,628.63 + + 13,573 + + 11,069.53 + + 27,748.53 + + 4,186 + + 2,830.92 + + 7,058.60 + + 191,940 + + 163,270.72 + + 409,035.59 + + 50,236 + + 42,879.28 + + 107,366.33 + + 131,558 + + 111,777.48 + + 280,226.21 + + 135,215 + + 113,849.75 + + 285,011.92 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/more-complex-columns-true-true-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/more-complex-columns-true-true-false-result.html index 31ec1c41..829da87b 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/more-complex-columns-true-true-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/more-complex-columns-true-true-false-result.html @@ -1,1226 +1,1226 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender -
      - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - F - - F - - F - - M - - M - - M -
      - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product -
      - All Products - - All Products - - All Products - - Drink - - Drink - - Drink - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer - - Beer - - Beer - - Good - - Good - - Good - - Good Imported Beer - - Good Imported Beer - - Good Imported Beer - - Good Light Beer - - Good Light Beer - - Good Light Beer - - Pearl - - Pearl - - Pearl - - Portsmouth - - Portsmouth - - Portsmouth - - Top Measure - - Top Measure - - Top Measure - - Walrus - - Walrus - - Walrus - - Wine - - Wine - - Wine - - Beverages - - Beverages - - Beverages - - Dairy - - Dairy - - Dairy - - Food - - Food - - Food - - Non-Consumable - - Non-Consumable - - Non-Consumable - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products -
      - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures -
      - Promotion Media - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - 266,773 - - 225,627.23 - - 565,238.13 - - 24,597 - - 19,477.23 - - 48,836.21 - - 6,838 - - 5,576.79 - - 14,029.08 - - 6,838 - - 5,576.79 - - 14,029.08 - - 1,683 - - 1,348.14 - - 3,400.45 - - 269 - - 198.21 - - 500.18 - - 154 - - 98.17 - - 249.48 - - 115 - - 100.04 - - 250.70 - - 385 - - 218.30 - - 549.85 - - 362 - - 412.24 - - 1,067.17 - - 306 - - 141.94 - - 343.04 - - 361 - - 377.45 - - 940.21 - - 5,155 - - 4,228.64 - - 10,628.63 - - 13,573 - - 11,069.53 - - 27,748.53 - - 4,186 - - 2,830.92 - - 7,058.60 - - 191,940 - - 163,270.72 - - 409,035.59 - - 50,236 - - 42,879.28 - - 107,366.33 - - 131,558 - - 111,777.48 - - 280,226.21 - - 135,215 - - 113,849.75 - - 285,011.92 -
      +   + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender +
      + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + F + + F + + F + + M + + M + + M +
      + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product +
      + All Products + + All Products + + All Products + + Drink + + Drink + + Drink + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer + + Beer + + Beer + + Good + + Good + + Good + + Good Imported Beer + + Good Imported Beer + + Good Imported Beer + + Good Light Beer + + Good Light Beer + + Good Light Beer + + Pearl + + Pearl + + Pearl + + Portsmouth + + Portsmouth + + Portsmouth + + Top Measure + + Top Measure + + Top Measure + + Walrus + + Walrus + + Walrus + + Wine + + Wine + + Wine + + Beverages + + Beverages + + Beverages + + Dairy + + Dairy + + Dairy + + Food + + Food + + Food + + Non-Consumable + + Non-Consumable + + Non-Consumable + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products +
      + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures +
      + Promotion Media + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + 266,773 + + 225,627.23 + + 565,238.13 + + 24,597 + + 19,477.23 + + 48,836.21 + + 6,838 + + 5,576.79 + + 14,029.08 + + 6,838 + + 5,576.79 + + 14,029.08 + + 1,683 + + 1,348.14 + + 3,400.45 + + 269 + + 198.21 + + 500.18 + + 154 + + 98.17 + + 249.48 + + 115 + + 100.04 + + 250.70 + + 385 + + 218.30 + + 549.85 + + 362 + + 412.24 + + 1,067.17 + + 306 + + 141.94 + + 343.04 + + 361 + + 377.45 + + 940.21 + + 5,155 + + 4,228.64 + + 10,628.63 + + 13,573 + + 11,069.53 + + 27,748.53 + + 4,186 + + 2,830.92 + + 7,058.60 + + 191,940 + + 163,270.72 + + 409,035.59 + + 50,236 + + 42,879.28 + + 107,366.33 + + 131,558 + + 111,777.48 + + 280,226.21 + + 135,215 + + 113,849.75 + + 285,011.92 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/more-complex-columns-true-true-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/more-complex-columns-true-true-true-result.html index 690598c4..5ca38983 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/more-complex-columns-true-true-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/more-complex-columns-true-true-true-result.html @@ -1,1774 +1,1774 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender - - Gender -
      - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender - - All Gender -
      - F - - F - - F - - M - - M - - M -
      - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product - - Product -
      - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products - - All Products -
      - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Drink - - Food - - Food - - Food - - Non-Consumable - - Non-Consumable - - Non-Consumable -
      - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Alcoholic Beverages - - Beverages - - Beverages - - Beverages - - Dairy - - Dairy - - Dairy -
      - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine - - Beer and Wine -
      - Beer - - Beer - - Beer - - Beer - - Beer - - Beer - - Beer - - Beer - - Beer - - Beer - - Beer - - Beer - - Beer - - Beer - - Beer - - Beer - - Beer - - Beer - - Beer - - Beer - - Beer - - Beer - - Beer - - Beer - - Wine - - Wine - - Wine -
      - Good - - Good - - Good - - Good - - Good - - Good - - Good - - Good - - Good - - Pearl - - Pearl - - Pearl - - Portsmouth - - Portsmouth - - Portsmouth - - Top Measure - - Top Measure - - Top Measure - - Walrus - - Walrus - - Walrus -
      - Good Imported Beer - - Good Imported Beer - - Good Imported Beer - - Good Light Beer - - Good Light Beer - - Good Light Beer -
      - Promotion Media - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures - - Measures -
      - (All) - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales - - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - 266,773 - - 225,627.23 - - 565,238.13 - - 24,597 - - 19,477.23 - - 48,836.21 - - 6,838 - - 5,576.79 - - 14,029.08 - - 6,838 - - 5,576.79 - - 14,029.08 - - 1,683 - - 1,348.14 - - 3,400.45 - - 269 - - 198.21 - - 500.18 - - 154 - - 98.17 - - 249.48 - - 115 - - 100.04 - - 250.70 - - 385 - - 218.30 - - 549.85 - - 362 - - 412.24 - - 1,067.17 - - 306 - - 141.94 - - 343.04 - - 361 - - 377.45 - - 940.21 - - 5,155 - - 4,228.64 - - 10,628.63 - - 13,573 - - 11,069.53 - - 27,748.53 - - 4,186 - - 2,830.92 - - 7,058.60 - - 191,940 - - 163,270.72 - - 409,035.59 - - 50,236 - - 42,879.28 - - 107,366.33 - - 131,558 - - 111,777.48 - - 280,226.21 - - 135,215 - - 113,849.75 - - 285,011.92 -
      +   + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender + + Gender +
      + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender + + All Gender +
      + F + + F + + F + + M + + M + + M +
      + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product + + Product +
      + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products + + All Products +
      + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Drink + + Food + + Food + + Food + + Non-Consumable + + Non-Consumable + + Non-Consumable +
      + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Alcoholic Beverages + + Beverages + + Beverages + + Beverages + + Dairy + + Dairy + + Dairy +
      + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine + + Beer and Wine +
      + Beer + + Beer + + Beer + + Beer + + Beer + + Beer + + Beer + + Beer + + Beer + + Beer + + Beer + + Beer + + Beer + + Beer + + Beer + + Beer + + Beer + + Beer + + Beer + + Beer + + Beer + + Beer + + Beer + + Beer + + Wine + + Wine + + Wine +
      + Good + + Good + + Good + + Good + + Good + + Good + + Good + + Good + + Good + + Pearl + + Pearl + + Pearl + + Portsmouth + + Portsmouth + + Portsmouth + + Top Measure + + Top Measure + + Top Measure + + Walrus + + Walrus + + Walrus +
      + Good Imported Beer + + Good Imported Beer + + Good Imported Beer + + Good Light Beer + + Good Light Beer + + Good Light Beer +
      + Promotion Media + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures + + Measures +
      + (All) + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales + + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + 266,773 + + 225,627.23 + + 565,238.13 + + 24,597 + + 19,477.23 + + 48,836.21 + + 6,838 + + 5,576.79 + + 14,029.08 + + 6,838 + + 5,576.79 + + 14,029.08 + + 1,683 + + 1,348.14 + + 3,400.45 + + 269 + + 198.21 + + 500.18 + + 154 + + 98.17 + + 249.48 + + 115 + + 100.04 + + 250.70 + + 385 + + 218.30 + + 549.85 + + 362 + + 412.24 + + 1,067.17 + + 306 + + 141.94 + + 343.04 + + 361 + + 377.45 + + 940.21 + + 5,155 + + 4,228.64 + + 10,628.63 + + 13,573 + + 11,069.53 + + 27,748.53 + + 4,186 + + 2,830.92 + + 7,058.60 + + 191,940 + + 163,270.72 + + 409,035.59 + + 50,236 + + 42,879.28 + + 107,366.33 + + 131,558 + + 111,777.48 + + 280,226.21 + + 135,215 + + 113,849.75 + + 285,011.92 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/parent-child-false-false-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/parent-child-false-false-false-result.html index 3a8d80f3..2ceb14fa 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/parent-child-false-false-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/parent-child-false-false-false-result.html @@ -1,110 +1,110 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Number of Employees -
      - All Employees - - 616 -
      - Sheri Nowmer - - 616 -
      - Derrick Whelply - - 603 -
      - Beverly Baker - - 79 -
      - Pedro Castillo - - 235 -
      - Laurie Borges - - 288 -
      - Michael Spence - -   -
      - Maya Gutierrez - -   -
      - Roberta Damstra - - 3 -
      - Rebecca Kanagaki - - 2 -
      - Darren Stanz - - 5 -
      - Donna Arnold - - 2 -
      +   + + Number of Employees +
      + All Employees + + 616 +
      + Sheri Nowmer + + 616 +
      + Derrick Whelply + + 603 +
      + Beverly Baker + + 79 +
      + Pedro Castillo + + 235 +
      + Laurie Borges + + 288 +
      + Michael Spence + +   +
      + Maya Gutierrez + +   +
      + Roberta Damstra + + 3 +
      + Rebecca Kanagaki + + 2 +
      + Darren Stanz + + 5 +
      + Donna Arnold + + 2 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/parent-child-false-false-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/parent-child-false-false-true-result.html index 5f3558d8..094b7a49 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/parent-child-false-false-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/parent-child-false-false-true-result.html @@ -1,119 +1,119 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Number of Employees -
      - All Employees - - 616 -
      - All Employees - - Sheri Nowmer - - 616 -
      - Sheri Nowmer - - Derrick Whelply - - 603 -
      - Derrick Whelply - - Beverly Baker - - 79 -
      - Pedro Castillo - - 235 -
      - Laurie Borges - - 288 -
      - Michael Spence - -   -
      - Maya Gutierrez - -   -
      - Roberta Damstra - - 3 -
      - Rebecca Kanagaki - - 2 -
      - Darren Stanz - - 5 -
      - Donna Arnold - - 2 -
      +   + + Number of Employees +
      + All Employees + + 616 +
      + All Employees + + Sheri Nowmer + + 616 +
      + Sheri Nowmer + + Derrick Whelply + + 603 +
      + Derrick Whelply + + Beverly Baker + + 79 +
      + Pedro Castillo + + 235 +
      + Laurie Borges + + 288 +
      + Michael Spence + +   +
      + Maya Gutierrez + +   +
      + Roberta Damstra + + 3 +
      + Rebecca Kanagaki + + 2 +
      + Darren Stanz + + 5 +
      + Donna Arnold + + 2 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/parent-child-false-true-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/parent-child-false-true-false-result.html index 5fdd3789..838752dc 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/parent-child-false-true-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/parent-child-false-true-false-result.html @@ -1,118 +1,118 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Measures -
      - Employees - - Number of Employees -
      - All Employees - - 616 -
      - Sheri Nowmer - - 616 -
      - Derrick Whelply - - 603 -
      - Beverly Baker - - 79 -
      - Pedro Castillo - - 235 -
      - Laurie Borges - - 288 -
      - Michael Spence - -   -
      - Maya Gutierrez - -   -
      - Roberta Damstra - - 3 -
      - Rebecca Kanagaki - - 2 -
      - Darren Stanz - - 5 -
      - Donna Arnold - - 2 -
      +   + + Measures +
      + Employees + + Number of Employees +
      + All Employees + + 616 +
      + Sheri Nowmer + + 616 +
      + Derrick Whelply + + 603 +
      + Beverly Baker + + 79 +
      + Pedro Castillo + + 235 +
      + Laurie Borges + + 288 +
      + Michael Spence + +   +
      + Maya Gutierrez + +   +
      + Roberta Damstra + + 3 +
      + Rebecca Kanagaki + + 2 +
      + Darren Stanz + + 5 +
      + Donna Arnold + + 2 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/parent-child-false-true-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/parent-child-false-true-true-result.html index 4d44dde5..494b505b 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/parent-child-false-true-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/parent-child-false-true-true-result.html @@ -1,136 +1,136 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      - Employees - - Measures -
      - (All) - - Employee Id - - Employee Id - - Employee Id - - Number of Employees -
      - All Employees - - 616 -
      - All Employees - - Sheri Nowmer - - 616 -
      - Sheri Nowmer - - Derrick Whelply - - 603 -
      - Derrick Whelply - - Beverly Baker - - 79 -
      - Pedro Castillo - - 235 -
      - Laurie Borges - - 288 -
      - Michael Spence - -   -
      - Maya Gutierrez - -   -
      - Roberta Damstra - - 3 -
      - Rebecca Kanagaki - - 2 -
      - Darren Stanz - - 5 -
      - Donna Arnold - - 2 -
      + Employees + + Measures +
      + (All) + + Employee Id + + Employee Id + + Employee Id + + Number of Employees +
      + All Employees + + 616 +
      + All Employees + + Sheri Nowmer + + 616 +
      + Sheri Nowmer + + Derrick Whelply + + 603 +
      + Derrick Whelply + + Beverly Baker + + 79 +
      + Pedro Castillo + + 235 +
      + Laurie Borges + + 288 +
      + Michael Spence + +   +
      + Maya Gutierrez + +   +
      + Roberta Damstra + + 3 +
      + Rebecca Kanagaki + + 2 +
      + Darren Stanz + + 5 +
      + Donna Arnold + + 2 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/parent-child-true-false-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/parent-child-true-false-false-result.html index 3a8d80f3..2ceb14fa 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/parent-child-true-false-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/parent-child-true-false-false-result.html @@ -1,110 +1,110 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Number of Employees -
      - All Employees - - 616 -
      - Sheri Nowmer - - 616 -
      - Derrick Whelply - - 603 -
      - Beverly Baker - - 79 -
      - Pedro Castillo - - 235 -
      - Laurie Borges - - 288 -
      - Michael Spence - -   -
      - Maya Gutierrez - -   -
      - Roberta Damstra - - 3 -
      - Rebecca Kanagaki - - 2 -
      - Darren Stanz - - 5 -
      - Donna Arnold - - 2 -
      +   + + Number of Employees +
      + All Employees + + 616 +
      + Sheri Nowmer + + 616 +
      + Derrick Whelply + + 603 +
      + Beverly Baker + + 79 +
      + Pedro Castillo + + 235 +
      + Laurie Borges + + 288 +
      + Michael Spence + +   +
      + Maya Gutierrez + +   +
      + Roberta Damstra + + 3 +
      + Rebecca Kanagaki + + 2 +
      + Darren Stanz + + 5 +
      + Donna Arnold + + 2 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/parent-child-true-false-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/parent-child-true-false-true-result.html index 793c94b1..4046e336 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/parent-child-true-false-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/parent-child-true-false-true-result.html @@ -1,182 +1,182 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Number of Employees -
      - All Employees - - 616 -
      - All Employees - - Sheri Nowmer - - 616 -
      - All Employees - - Sheri Nowmer - - Derrick Whelply - - 603 -
      - All Employees - - Sheri Nowmer - - Derrick Whelply - - Beverly Baker - - 79 -
      - All Employees - - Sheri Nowmer - - Derrick Whelply - - Pedro Castillo - - 235 -
      - All Employees - - Sheri Nowmer - - Derrick Whelply - - Laurie Borges - - 288 -
      - All Employees - - Sheri Nowmer - - Michael Spence - -   -
      - All Employees - - Sheri Nowmer - - Maya Gutierrez - -   -
      - All Employees - - Sheri Nowmer - - Roberta Damstra - - 3 -
      - All Employees - - Sheri Nowmer - - Rebecca Kanagaki - - 2 -
      - All Employees - - Sheri Nowmer - - Darren Stanz - - 5 -
      - All Employees - - Sheri Nowmer - - Donna Arnold - - 2 -
      +   + + Number of Employees +
      + All Employees + + 616 +
      + All Employees + + Sheri Nowmer + + 616 +
      + All Employees + + Sheri Nowmer + + Derrick Whelply + + 603 +
      + All Employees + + Sheri Nowmer + + Derrick Whelply + + Beverly Baker + + 79 +
      + All Employees + + Sheri Nowmer + + Derrick Whelply + + Pedro Castillo + + 235 +
      + All Employees + + Sheri Nowmer + + Derrick Whelply + + Laurie Borges + + 288 +
      + All Employees + + Sheri Nowmer + + Michael Spence + +   +
      + All Employees + + Sheri Nowmer + + Maya Gutierrez + +   +
      + All Employees + + Sheri Nowmer + + Roberta Damstra + + 3 +
      + All Employees + + Sheri Nowmer + + Rebecca Kanagaki + + 2 +
      + All Employees + + Sheri Nowmer + + Darren Stanz + + 5 +
      + All Employees + + Sheri Nowmer + + Donna Arnold + + 2 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/parent-child-true-true-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/parent-child-true-true-false-result.html index 5fdd3789..838752dc 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/parent-child-true-true-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/parent-child-true-true-false-result.html @@ -1,118 +1,118 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Measures -
      - Employees - - Number of Employees -
      - All Employees - - 616 -
      - Sheri Nowmer - - 616 -
      - Derrick Whelply - - 603 -
      - Beverly Baker - - 79 -
      - Pedro Castillo - - 235 -
      - Laurie Borges - - 288 -
      - Michael Spence - -   -
      - Maya Gutierrez - -   -
      - Roberta Damstra - - 3 -
      - Rebecca Kanagaki - - 2 -
      - Darren Stanz - - 5 -
      - Donna Arnold - - 2 -
      +   + + Measures +
      + Employees + + Number of Employees +
      + All Employees + + 616 +
      + Sheri Nowmer + + 616 +
      + Derrick Whelply + + 603 +
      + Beverly Baker + + 79 +
      + Pedro Castillo + + 235 +
      + Laurie Borges + + 288 +
      + Michael Spence + +   +
      + Maya Gutierrez + +   +
      + Roberta Damstra + + 3 +
      + Rebecca Kanagaki + + 2 +
      + Darren Stanz + + 5 +
      + Donna Arnold + + 2 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/parent-child-true-true-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/parent-child-true-true-true-result.html index 236eebf3..2008b3e5 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/parent-child-true-true-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/parent-child-true-true-true-result.html @@ -1,199 +1,199 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      - Employees - - Measures -
      - (All) - - Employee Id - - Employee Id - - Employee Id - - Number of Employees -
      - All Employees - - 616 -
      - All Employees - - Sheri Nowmer - - 616 -
      - All Employees - - Sheri Nowmer - - Derrick Whelply - - 603 -
      - All Employees - - Sheri Nowmer - - Derrick Whelply - - Beverly Baker - - 79 -
      - All Employees - - Sheri Nowmer - - Derrick Whelply - - Pedro Castillo - - 235 -
      - All Employees - - Sheri Nowmer - - Derrick Whelply - - Laurie Borges - - 288 -
      - All Employees - - Sheri Nowmer - - Michael Spence - -   -
      - All Employees - - Sheri Nowmer - - Maya Gutierrez - -   -
      - All Employees - - Sheri Nowmer - - Roberta Damstra - - 3 -
      - All Employees - - Sheri Nowmer - - Rebecca Kanagaki - - 2 -
      - All Employees - - Sheri Nowmer - - Darren Stanz - - 5 -
      - All Employees - - Sheri Nowmer - - Donna Arnold - - 2 -
      + Employees + + Measures +
      + (All) + + Employee Id + + Employee Id + + Employee Id + + Number of Employees +
      + All Employees + + 616 +
      + All Employees + + Sheri Nowmer + + 616 +
      + All Employees + + Sheri Nowmer + + Derrick Whelply + + 603 +
      + All Employees + + Sheri Nowmer + + Derrick Whelply + + Beverly Baker + + 79 +
      + All Employees + + Sheri Nowmer + + Derrick Whelply + + Pedro Castillo + + 235 +
      + All Employees + + Sheri Nowmer + + Derrick Whelply + + Laurie Borges + + 288 +
      + All Employees + + Sheri Nowmer + + Michael Spence + +   +
      + All Employees + + Sheri Nowmer + + Maya Gutierrez + +   +
      + All Employees + + Sheri Nowmer + + Roberta Damstra + + 3 +
      + All Employees + + Sheri Nowmer + + Rebecca Kanagaki + + 2 +
      + All Employees + + Sheri Nowmer + + Darren Stanz + + 5 +
      + All Employees + + Sheri Nowmer + + Donna Arnold + + 2 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/ragged-false-false-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/ragged-false-false-false-result.html index 0099c86f..f9a05fea 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/ragged-false-false-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/ragged-false-false-false-result.html @@ -1,104 +1,104 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Store Sales - - Store Cost - - Unit Sales -
      - Israel - - 29,035.20 - - 11,594.15 - - 13,694 -
      - Haifa - - 4,705.97 - - 1,880.34 - - 2,203 -
      - Store 22 - - 4,705.97 - - 1,880.34 - - 2,203 -
      - Tel Aviv - - 24,329.23 - - 9,713.81 - - 11,491 -
      - USA - - 461,358.97 - - 184,073.80 - - 217,822 -
      - Vatican - - 74,843.96 - - 29,959.28 - - 35,257 -
      +   + + Store Sales + + Store Cost + + Unit Sales +
      + Israel + + 29,035.20 + + 11,594.15 + + 13,694 +
      + Haifa + + 4,705.97 + + 1,880.34 + + 2,203 +
      + Store 22 + + 4,705.97 + + 1,880.34 + + 2,203 +
      + Tel Aviv + + 24,329.23 + + 9,713.81 + + 11,491 +
      + USA + + 461,358.97 + + 184,073.80 + + 217,822 +
      + Vatican + + 74,843.96 + + 29,959.28 + + 35,257 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/ragged-false-false-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/ragged-false-false-true-result.html index 5e495b77..aca424f5 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/ragged-false-false-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/ragged-false-false-true-result.html @@ -1,116 +1,116 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Store Sales - - Store Cost - - Unit Sales -
      - All Stores - - Israel - - 29,035.20 - - 11,594.15 - - 13,694 -
      - Israel - -   - - Haifa - - 4,705.97 - - 1,880.34 - - 2,203 -
      - Haifa - - Store 22 - - 4,705.97 - - 1,880.34 - - 2,203 -
      - Tel Aviv - - 24,329.23 - - 9,713.81 - - 11,491 -
      - USA - - 461,358.97 - - 184,073.80 - - 217,822 -
      - Vatican - - 74,843.96 - - 29,959.28 - - 35,257 -
      +   + + Store Sales + + Store Cost + + Unit Sales +
      + All Stores + + Israel + + 29,035.20 + + 11,594.15 + + 13,694 +
      + Israel + +   + + Haifa + + 4,705.97 + + 1,880.34 + + 2,203 +
      + Haifa + + Store 22 + + 4,705.97 + + 1,880.34 + + 2,203 +
      + Tel Aviv + + 24,329.23 + + 9,713.81 + + 11,491 +
      + USA + + 461,358.97 + + 184,073.80 + + 217,822 +
      + Vatican + + 74,843.96 + + 29,959.28 + + 35,257 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/ragged-false-true-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/ragged-false-true-false-result.html index 3048e21e..5823d8e8 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/ragged-false-true-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/ragged-false-true-false-result.html @@ -1,112 +1,112 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Measures -
      - Store - - Store Sales - - Store Cost - - Unit Sales -
      - Israel - - 29,035.20 - - 11,594.15 - - 13,694 -
      - Haifa - - 4,705.97 - - 1,880.34 - - 2,203 -
      - Store 22 - - 4,705.97 - - 1,880.34 - - 2,203 -
      - Tel Aviv - - 24,329.23 - - 9,713.81 - - 11,491 -
      - USA - - 461,358.97 - - 184,073.80 - - 217,822 -
      - Vatican - - 74,843.96 - - 29,959.28 - - 35,257 -
      +   + + Measures +
      + Store + + Store Sales + + Store Cost + + Unit Sales +
      + Israel + + 29,035.20 + + 11,594.15 + + 13,694 +
      + Haifa + + 4,705.97 + + 1,880.34 + + 2,203 +
      + Store 22 + + 4,705.97 + + 1,880.34 + + 2,203 +
      + Tel Aviv + + 24,329.23 + + 9,713.81 + + 11,491 +
      + USA + + 461,358.97 + + 184,073.80 + + 217,822 +
      + Vatican + + 74,843.96 + + 29,959.28 + + 35,257 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/ragged-false-true-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/ragged-false-true-true-result.html index c1966212..4c97d95e 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/ragged-false-true-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/ragged-false-true-true-result.html @@ -1,136 +1,136 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      - Store - - Measures -
      - (All) - - Store Country - - Store State - - Store City - - Store Name - - Store Sales - - Store Cost - - Unit Sales -
      - All Stores - - Israel - - 29,035.20 - - 11,594.15 - - 13,694 -
      - Israel - -   - - Haifa - - 4,705.97 - - 1,880.34 - - 2,203 -
      - Haifa - - Store 22 - - 4,705.97 - - 1,880.34 - - 2,203 -
      - Tel Aviv - - 24,329.23 - - 9,713.81 - - 11,491 -
      - USA - - 461,358.97 - - 184,073.80 - - 217,822 -
      - Vatican - - 74,843.96 - - 29,959.28 - - 35,257 -
      + Store + + Measures +
      + (All) + + Store Country + + Store State + + Store City + + Store Name + + Store Sales + + Store Cost + + Unit Sales +
      + All Stores + + Israel + + 29,035.20 + + 11,594.15 + + 13,694 +
      + Israel + +   + + Haifa + + 4,705.97 + + 1,880.34 + + 2,203 +
      + Haifa + + Store 22 + + 4,705.97 + + 1,880.34 + + 2,203 +
      + Tel Aviv + + 24,329.23 + + 9,713.81 + + 11,491 +
      + USA + + 461,358.97 + + 184,073.80 + + 217,822 +
      + Vatican + + 74,843.96 + + 29,959.28 + + 35,257 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/ragged-true-false-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/ragged-true-false-false-result.html index 0099c86f..f9a05fea 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/ragged-true-false-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/ragged-true-false-false-result.html @@ -1,104 +1,104 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Store Sales - - Store Cost - - Unit Sales -
      - Israel - - 29,035.20 - - 11,594.15 - - 13,694 -
      - Haifa - - 4,705.97 - - 1,880.34 - - 2,203 -
      - Store 22 - - 4,705.97 - - 1,880.34 - - 2,203 -
      - Tel Aviv - - 24,329.23 - - 9,713.81 - - 11,491 -
      - USA - - 461,358.97 - - 184,073.80 - - 217,822 -
      - Vatican - - 74,843.96 - - 29,959.28 - - 35,257 -
      +   + + Store Sales + + Store Cost + + Unit Sales +
      + Israel + + 29,035.20 + + 11,594.15 + + 13,694 +
      + Haifa + + 4,705.97 + + 1,880.34 + + 2,203 +
      + Store 22 + + 4,705.97 + + 1,880.34 + + 2,203 +
      + Tel Aviv + + 24,329.23 + + 9,713.81 + + 11,491 +
      + USA + + 461,358.97 + + 184,073.80 + + 217,822 +
      + Vatican + + 74,843.96 + + 29,959.28 + + 35,257 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/ragged-true-false-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/ragged-true-false-true-result.html index 1842f85c..e5111efa 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/ragged-true-false-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/ragged-true-false-true-result.html @@ -1,143 +1,143 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Store Sales - - Store Cost - - Unit Sales -
      - All Stores - - Israel - - 29,035.20 - - 11,594.15 - - 13,694 -
      - All Stores - - Israel - -   - - Haifa - - 4,705.97 - - 1,880.34 - - 2,203 -
      - All Stores - - Israel - -   - - Haifa - - Store 22 - - 4,705.97 - - 1,880.34 - - 2,203 -
      - All Stores - - Israel - -   - - Tel Aviv - - 24,329.23 - - 9,713.81 - - 11,491 -
      - All Stores - - USA - - 461,358.97 - - 184,073.80 - - 217,822 -
      - All Stores - - Vatican - - 74,843.96 - - 29,959.28 - - 35,257 -
      +   + + Store Sales + + Store Cost + + Unit Sales +
      + All Stores + + Israel + + 29,035.20 + + 11,594.15 + + 13,694 +
      + All Stores + + Israel + +   + + Haifa + + 4,705.97 + + 1,880.34 + + 2,203 +
      + All Stores + + Israel + +   + + Haifa + + Store 22 + + 4,705.97 + + 1,880.34 + + 2,203 +
      + All Stores + + Israel + +   + + Tel Aviv + + 24,329.23 + + 9,713.81 + + 11,491 +
      + All Stores + + USA + + 461,358.97 + + 184,073.80 + + 217,822 +
      + All Stores + + Vatican + + 74,843.96 + + 29,959.28 + + 35,257 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/ragged-true-true-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/ragged-true-true-false-result.html index c3b32b92..9f1918cd 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/ragged-true-true-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/ragged-true-true-false-result.html @@ -1,118 +1,118 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Measures - - Measures - - Measures -
      - Store - - Store Sales - - Store Cost - - Unit Sales -
      - Israel - - 29,035.20 - - 11,594.15 - - 13,694 -
      - Haifa - - 4,705.97 - - 1,880.34 - - 2,203 -
      - Store 22 - - 4,705.97 - - 1,880.34 - - 2,203 -
      - Tel Aviv - - 24,329.23 - - 9,713.81 - - 11,491 -
      - USA - - 461,358.97 - - 184,073.80 - - 217,822 -
      - Vatican - - 74,843.96 - - 29,959.28 - - 35,257 -
      +   + + Measures + + Measures + + Measures +
      + Store + + Store Sales + + Store Cost + + Unit Sales +
      + Israel + + 29,035.20 + + 11,594.15 + + 13,694 +
      + Haifa + + 4,705.97 + + 1,880.34 + + 2,203 +
      + Store 22 + + 4,705.97 + + 1,880.34 + + 2,203 +
      + Tel Aviv + + 24,329.23 + + 9,713.81 + + 11,491 +
      + USA + + 461,358.97 + + 184,073.80 + + 217,822 +
      + Vatican + + 74,843.96 + + 29,959.28 + + 35,257 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/ragged-true-true-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/ragged-true-true-true-result.html index 2e0f3365..4dad9415 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/ragged-true-true-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/ragged-true-true-true-result.html @@ -1,169 +1,169 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      - Store - - Measures - - Measures - - Measures -
      - (All) - - Store Country - - Store State - - Store City - - Store Name - - Store Sales - - Store Cost - - Unit Sales -
      - All Stores - - Israel - - 29,035.20 - - 11,594.15 - - 13,694 -
      - All Stores - - Israel - -   - - Haifa - - 4,705.97 - - 1,880.34 - - 2,203 -
      - All Stores - - Israel - -   - - Haifa - - Store 22 - - 4,705.97 - - 1,880.34 - - 2,203 -
      - All Stores - - Israel - -   - - Tel Aviv - - 24,329.23 - - 9,713.81 - - 11,491 -
      - All Stores - - USA - - 461,358.97 - - 184,073.80 - - 217,822 -
      - All Stores - - Vatican - - 74,843.96 - - 29,959.28 - - 35,257 -
      + Store + + Measures + + Measures + + Measures +
      + (All) + + Store Country + + Store State + + Store City + + Store Name + + Store Sales + + Store Cost + + Unit Sales +
      + All Stores + + Israel + + 29,035.20 + + 11,594.15 + + 13,694 +
      + All Stores + + Israel + +   + + Haifa + + 4,705.97 + + 1,880.34 + + 2,203 +
      + All Stores + + Israel + +   + + Haifa + + Store 22 + + 4,705.97 + + 1,880.34 + + 2,203 +
      + All Stores + + Israel + +   + + Tel Aviv + + 24,329.23 + + 9,713.81 + + 11,491 +
      + All Stores + + USA + + 461,358.97 + + 184,073.80 + + 217,822 +
      + All Stores + + Vatican + + 74,843.96 + + 29,959.28 + + 35,257 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/single-dim-crossjoin-false-false-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/single-dim-crossjoin-false-false-false-result.html index c14eb535..d9f42c59 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/single-dim-crossjoin-false-false-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/single-dim-crossjoin-false-false-false-result.html @@ -1,849 +1,849 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Store Sales -
      - 1997 - - 1 - - 11,734.43 -
      - 2 - - 19,756.43 -
      - 3 - - 19,933.22 -
      - 4 - - 10,640.96 -
      - 5 - - 12,339.06 -
      - 6 - - 5,485.97 -
      - 7 - - 11,368.84 -
      - 8 - - 12,762.95 -
      - 9 - - 11,095.62 -
      - 10 - - 9,205.40 -
      - 11 - - 7,775.74 -
      - 12 - - 13,083.95 -
      - 13 - - 18,164.50 -
      - 14 - - 9,086.91 -
      - 15 - - 9,534.01 -
      - 16 - - 8,099.97 -
      - 17 - - 14,361.15 -
      - 18 - - 8,055.59 -
      - 19 - - 10,046.38 -
      - 20 - - 14,158.00 -
      - 21 - - 9,629.54 -
      - 22 - - 8,962.98 -
      - 23 - - 5,178.50 -
      - 24 - - 11,371.84 -
      - 25 - - 6,601.20 -
      - 26 - - 16,382.53 -
      - 27 - - 9,821.26 -
      - 28 - - 12,408.58 -
      - 29 - - 11,010.72 -
      - 30 - - 5,381.41 -
      - 31 - - 10,383.56 -
      - 32 - - 14,748.60 -
      - 33 - - 10,048.16 -
      - 34 - - 13,251.68 -
      - 35 - - 9,789.56 -
      - 36 - - 10,578.55 -
      - 37 - - 8,956.30 -
      - 38 - - 13,454.83 -
      - 39 - - 11,885.60 -
      - 40 - - 8,569.53 -
      - 41 - - 4,560.28 -
      - 42 - - 8,849.83 -
      - 43 - - 14,110.56 -
      - 44 - - 12,045.58 -
      - 45 - - 4,707.93 -
      - 46 - - 12,753.39 -
      - 47 - - 12,406.81 -
      - 48 - - 14,353.49 -
      - 49 - - 11,425.66 -
      - 50 - - 11,184.85 -
      - 51 - - 11,880.04 -
      - 52 - - 1,855.70 -
      - 1 - -   -
      - 2 - -   -
      - 3 - -   -
      - 4 - -   -
      - 5 - -   -
      - 6 - -   -
      - 7 - -   -
      - 8 - -   -
      - 9 - -   -
      - 10 - -   -
      - 11 - -   -
      - 12 - -   -
      - 13 - -   -
      - 14 - -   -
      - 15 - -   -
      - 16 - -   -
      - 17 - -   -
      - 18 - -   -
      - 19 - -   -
      - 20 - -   -
      - 21 - -   -
      - 22 - -   -
      - 23 - -   -
      - 24 - -   -
      - 25 - -   -
      - 26 - -   -
      - 27 - -   -
      - 28 - -   -
      - 29 - -   -
      - 30 - -   -
      - 31 - -   -
      - 32 - -   -
      - 33 - -   -
      - 34 - -   -
      - 35 - -   -
      - 36 - -   -
      - 37 - -   -
      - 38 - -   -
      - 39 - -   -
      - 40 - -   -
      - 41 - -   -
      - 42 - -   -
      - 43 - -   -
      - 44 - -   -
      - 45 - -   -
      - 46 - -   -
      - 47 - -   -
      - 48 - -   -
      - 49 - -   -
      - 50 - -   -
      - 51 - -   -
      - 52 - -   -
      +   + + Store Sales +
      + 1997 + + 1 + + 11,734.43 +
      + 2 + + 19,756.43 +
      + 3 + + 19,933.22 +
      + 4 + + 10,640.96 +
      + 5 + + 12,339.06 +
      + 6 + + 5,485.97 +
      + 7 + + 11,368.84 +
      + 8 + + 12,762.95 +
      + 9 + + 11,095.62 +
      + 10 + + 9,205.40 +
      + 11 + + 7,775.74 +
      + 12 + + 13,083.95 +
      + 13 + + 18,164.50 +
      + 14 + + 9,086.91 +
      + 15 + + 9,534.01 +
      + 16 + + 8,099.97 +
      + 17 + + 14,361.15 +
      + 18 + + 8,055.59 +
      + 19 + + 10,046.38 +
      + 20 + + 14,158.00 +
      + 21 + + 9,629.54 +
      + 22 + + 8,962.98 +
      + 23 + + 5,178.50 +
      + 24 + + 11,371.84 +
      + 25 + + 6,601.20 +
      + 26 + + 16,382.53 +
      + 27 + + 9,821.26 +
      + 28 + + 12,408.58 +
      + 29 + + 11,010.72 +
      + 30 + + 5,381.41 +
      + 31 + + 10,383.56 +
      + 32 + + 14,748.60 +
      + 33 + + 10,048.16 +
      + 34 + + 13,251.68 +
      + 35 + + 9,789.56 +
      + 36 + + 10,578.55 +
      + 37 + + 8,956.30 +
      + 38 + + 13,454.83 +
      + 39 + + 11,885.60 +
      + 40 + + 8,569.53 +
      + 41 + + 4,560.28 +
      + 42 + + 8,849.83 +
      + 43 + + 14,110.56 +
      + 44 + + 12,045.58 +
      + 45 + + 4,707.93 +
      + 46 + + 12,753.39 +
      + 47 + + 12,406.81 +
      + 48 + + 14,353.49 +
      + 49 + + 11,425.66 +
      + 50 + + 11,184.85 +
      + 51 + + 11,880.04 +
      + 52 + + 1,855.70 +
      + 1 + +   +
      + 2 + +   +
      + 3 + +   +
      + 4 + +   +
      + 5 + +   +
      + 6 + +   +
      + 7 + +   +
      + 8 + +   +
      + 9 + +   +
      + 10 + +   +
      + 11 + +   +
      + 12 + +   +
      + 13 + +   +
      + 14 + +   +
      + 15 + +   +
      + 16 + +   +
      + 17 + +   +
      + 18 + +   +
      + 19 + +   +
      + 20 + +   +
      + 21 + +   +
      + 22 + +   +
      + 23 + +   +
      + 24 + +   +
      + 25 + +   +
      + 26 + +   +
      + 27 + +   +
      + 28 + +   +
      + 29 + +   +
      + 30 + +   +
      + 31 + +   +
      + 32 + +   +
      + 33 + +   +
      + 34 + +   +
      + 35 + +   +
      + 36 + +   +
      + 37 + +   +
      + 38 + +   +
      + 39 + +   +
      + 40 + +   +
      + 41 + +   +
      + 42 + +   +
      + 43 + +   +
      + 44 + +   +
      + 45 + +   +
      + 46 + +   +
      + 47 + +   +
      + 48 + +   +
      + 49 + +   +
      + 50 + +   +
      + 51 + +   +
      + 52 + +   +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/single-dim-crossjoin-false-false-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/single-dim-crossjoin-false-false-true-result.html index e832a155..65af8306 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/single-dim-crossjoin-false-false-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/single-dim-crossjoin-false-false-true-result.html @@ -1,858 +1,858 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Store Sales -
      - 1997 - - All Time.Weeklys - - 1997 - - 1 - - 11,734.43 -
      - 2 - - 19,756.43 -
      - 3 - - 19,933.22 -
      - 4 - - 10,640.96 -
      - 5 - - 12,339.06 -
      - 6 - - 5,485.97 -
      - 7 - - 11,368.84 -
      - 8 - - 12,762.95 -
      - 9 - - 11,095.62 -
      - 10 - - 9,205.40 -
      - 11 - - 7,775.74 -
      - 12 - - 13,083.95 -
      - 13 - - 18,164.50 -
      - 14 - - 9,086.91 -
      - 15 - - 9,534.01 -
      - 16 - - 8,099.97 -
      - 17 - - 14,361.15 -
      - 18 - - 8,055.59 -
      - 19 - - 10,046.38 -
      - 20 - - 14,158.00 -
      - 21 - - 9,629.54 -
      - 22 - - 8,962.98 -
      - 23 - - 5,178.50 -
      - 24 - - 11,371.84 -
      - 25 - - 6,601.20 -
      - 26 - - 16,382.53 -
      - 27 - - 9,821.26 -
      - 28 - - 12,408.58 -
      - 29 - - 11,010.72 -
      - 30 - - 5,381.41 -
      - 31 - - 10,383.56 -
      - 32 - - 14,748.60 -
      - 33 - - 10,048.16 -
      - 34 - - 13,251.68 -
      - 35 - - 9,789.56 -
      - 36 - - 10,578.55 -
      - 37 - - 8,956.30 -
      - 38 - - 13,454.83 -
      - 39 - - 11,885.60 -
      - 40 - - 8,569.53 -
      - 41 - - 4,560.28 -
      - 42 - - 8,849.83 -
      - 43 - - 14,110.56 -
      - 44 - - 12,045.58 -
      - 45 - - 4,707.93 -
      - 46 - - 12,753.39 -
      - 47 - - 12,406.81 -
      - 48 - - 14,353.49 -
      - 49 - - 11,425.66 -
      - 50 - - 11,184.85 -
      - 51 - - 11,880.04 -
      - 52 - - 1,855.70 -
      - 1998 - - 1 - -   -
      - 2 - -   -
      - 3 - -   -
      - 4 - -   -
      - 5 - -   -
      - 6 - -   -
      - 7 - -   -
      - 8 - -   -
      - 9 - -   -
      - 10 - -   -
      - 11 - -   -
      - 12 - -   -
      - 13 - -   -
      - 14 - -   -
      - 15 - -   -
      - 16 - -   -
      - 17 - -   -
      - 18 - -   -
      - 19 - -   -
      - 20 - -   -
      - 21 - -   -
      - 22 - -   -
      - 23 - -   -
      - 24 - -   -
      - 25 - -   -
      - 26 - -   -
      - 27 - -   -
      - 28 - -   -
      - 29 - -   -
      - 30 - -   -
      - 31 - -   -
      - 32 - -   -
      - 33 - -   -
      - 34 - -   -
      - 35 - -   -
      - 36 - -   -
      - 37 - -   -
      - 38 - -   -
      - 39 - -   -
      - 40 - -   -
      - 41 - -   -
      - 42 - -   -
      - 43 - -   -
      - 44 - -   -
      - 45 - -   -
      - 46 - -   -
      - 47 - -   -
      - 48 - -   -
      - 49 - -   -
      - 50 - -   -
      - 51 - -   -
      - 52 - -   -
      +   + + Store Sales +
      + 1997 + + All Time.Weeklys + + 1997 + + 1 + + 11,734.43 +
      + 2 + + 19,756.43 +
      + 3 + + 19,933.22 +
      + 4 + + 10,640.96 +
      + 5 + + 12,339.06 +
      + 6 + + 5,485.97 +
      + 7 + + 11,368.84 +
      + 8 + + 12,762.95 +
      + 9 + + 11,095.62 +
      + 10 + + 9,205.40 +
      + 11 + + 7,775.74 +
      + 12 + + 13,083.95 +
      + 13 + + 18,164.50 +
      + 14 + + 9,086.91 +
      + 15 + + 9,534.01 +
      + 16 + + 8,099.97 +
      + 17 + + 14,361.15 +
      + 18 + + 8,055.59 +
      + 19 + + 10,046.38 +
      + 20 + + 14,158.00 +
      + 21 + + 9,629.54 +
      + 22 + + 8,962.98 +
      + 23 + + 5,178.50 +
      + 24 + + 11,371.84 +
      + 25 + + 6,601.20 +
      + 26 + + 16,382.53 +
      + 27 + + 9,821.26 +
      + 28 + + 12,408.58 +
      + 29 + + 11,010.72 +
      + 30 + + 5,381.41 +
      + 31 + + 10,383.56 +
      + 32 + + 14,748.60 +
      + 33 + + 10,048.16 +
      + 34 + + 13,251.68 +
      + 35 + + 9,789.56 +
      + 36 + + 10,578.55 +
      + 37 + + 8,956.30 +
      + 38 + + 13,454.83 +
      + 39 + + 11,885.60 +
      + 40 + + 8,569.53 +
      + 41 + + 4,560.28 +
      + 42 + + 8,849.83 +
      + 43 + + 14,110.56 +
      + 44 + + 12,045.58 +
      + 45 + + 4,707.93 +
      + 46 + + 12,753.39 +
      + 47 + + 12,406.81 +
      + 48 + + 14,353.49 +
      + 49 + + 11,425.66 +
      + 50 + + 11,184.85 +
      + 51 + + 11,880.04 +
      + 52 + + 1,855.70 +
      + 1998 + + 1 + +   +
      + 2 + +   +
      + 3 + +   +
      + 4 + +   +
      + 5 + +   +
      + 6 + +   +
      + 7 + +   +
      + 8 + +   +
      + 9 + +   +
      + 10 + +   +
      + 11 + +   +
      + 12 + +   +
      + 13 + +   +
      + 14 + +   +
      + 15 + +   +
      + 16 + +   +
      + 17 + +   +
      + 18 + +   +
      + 19 + +   +
      + 20 + +   +
      + 21 + +   +
      + 22 + +   +
      + 23 + +   +
      + 24 + +   +
      + 25 + +   +
      + 26 + +   +
      + 27 + +   +
      + 28 + +   +
      + 29 + +   +
      + 30 + +   +
      + 31 + +   +
      + 32 + +   +
      + 33 + +   +
      + 34 + +   +
      + 35 + +   +
      + 36 + +   +
      + 37 + +   +
      + 38 + +   +
      + 39 + +   +
      + 40 + +   +
      + 41 + +   +
      + 42 + +   +
      + 43 + +   +
      + 44 + +   +
      + 45 + +   +
      + 46 + +   +
      + 47 + +   +
      + 48 + +   +
      + 49 + +   +
      + 50 + +   +
      + 51 + +   +
      + 52 + +   +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/single-dim-crossjoin-false-true-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/single-dim-crossjoin-false-true-false-result.html index 0d416198..44f3f30e 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/single-dim-crossjoin-false-true-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/single-dim-crossjoin-false-true-false-result.html @@ -1,860 +1,860 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Measures -
      - Time - - Weekly - - Store Sales -
      - 1997 - - 1 - - 11,734.43 -
      - 2 - - 19,756.43 -
      - 3 - - 19,933.22 -
      - 4 - - 10,640.96 -
      - 5 - - 12,339.06 -
      - 6 - - 5,485.97 -
      - 7 - - 11,368.84 -
      - 8 - - 12,762.95 -
      - 9 - - 11,095.62 -
      - 10 - - 9,205.40 -
      - 11 - - 7,775.74 -
      - 12 - - 13,083.95 -
      - 13 - - 18,164.50 -
      - 14 - - 9,086.91 -
      - 15 - - 9,534.01 -
      - 16 - - 8,099.97 -
      - 17 - - 14,361.15 -
      - 18 - - 8,055.59 -
      - 19 - - 10,046.38 -
      - 20 - - 14,158.00 -
      - 21 - - 9,629.54 -
      - 22 - - 8,962.98 -
      - 23 - - 5,178.50 -
      - 24 - - 11,371.84 -
      - 25 - - 6,601.20 -
      - 26 - - 16,382.53 -
      - 27 - - 9,821.26 -
      - 28 - - 12,408.58 -
      - 29 - - 11,010.72 -
      - 30 - - 5,381.41 -
      - 31 - - 10,383.56 -
      - 32 - - 14,748.60 -
      - 33 - - 10,048.16 -
      - 34 - - 13,251.68 -
      - 35 - - 9,789.56 -
      - 36 - - 10,578.55 -
      - 37 - - 8,956.30 -
      - 38 - - 13,454.83 -
      - 39 - - 11,885.60 -
      - 40 - - 8,569.53 -
      - 41 - - 4,560.28 -
      - 42 - - 8,849.83 -
      - 43 - - 14,110.56 -
      - 44 - - 12,045.58 -
      - 45 - - 4,707.93 -
      - 46 - - 12,753.39 -
      - 47 - - 12,406.81 -
      - 48 - - 14,353.49 -
      - 49 - - 11,425.66 -
      - 50 - - 11,184.85 -
      - 51 - - 11,880.04 -
      - 52 - - 1,855.70 -
      - 1 - -   -
      - 2 - -   -
      - 3 - -   -
      - 4 - -   -
      - 5 - -   -
      - 6 - -   -
      - 7 - -   -
      - 8 - -   -
      - 9 - -   -
      - 10 - -   -
      - 11 - -   -
      - 12 - -   -
      - 13 - -   -
      - 14 - -   -
      - 15 - -   -
      - 16 - -   -
      - 17 - -   -
      - 18 - -   -
      - 19 - -   -
      - 20 - -   -
      - 21 - -   -
      - 22 - -   -
      - 23 - -   -
      - 24 - -   -
      - 25 - -   -
      - 26 - -   -
      - 27 - -   -
      - 28 - -   -
      - 29 - -   -
      - 30 - -   -
      - 31 - -   -
      - 32 - -   -
      - 33 - -   -
      - 34 - -   -
      - 35 - -   -
      - 36 - -   -
      - 37 - -   -
      - 38 - -   -
      - 39 - -   -
      - 40 - -   -
      - 41 - -   -
      - 42 - -   -
      - 43 - -   -
      - 44 - -   -
      - 45 - -   -
      - 46 - -   -
      - 47 - -   -
      - 48 - -   -
      - 49 - -   -
      - 50 - -   -
      - 51 - -   -
      - 52 - -   -
      +   + + Measures +
      + Time + + Weekly + + Store Sales +
      + 1997 + + 1 + + 11,734.43 +
      + 2 + + 19,756.43 +
      + 3 + + 19,933.22 +
      + 4 + + 10,640.96 +
      + 5 + + 12,339.06 +
      + 6 + + 5,485.97 +
      + 7 + + 11,368.84 +
      + 8 + + 12,762.95 +
      + 9 + + 11,095.62 +
      + 10 + + 9,205.40 +
      + 11 + + 7,775.74 +
      + 12 + + 13,083.95 +
      + 13 + + 18,164.50 +
      + 14 + + 9,086.91 +
      + 15 + + 9,534.01 +
      + 16 + + 8,099.97 +
      + 17 + + 14,361.15 +
      + 18 + + 8,055.59 +
      + 19 + + 10,046.38 +
      + 20 + + 14,158.00 +
      + 21 + + 9,629.54 +
      + 22 + + 8,962.98 +
      + 23 + + 5,178.50 +
      + 24 + + 11,371.84 +
      + 25 + + 6,601.20 +
      + 26 + + 16,382.53 +
      + 27 + + 9,821.26 +
      + 28 + + 12,408.58 +
      + 29 + + 11,010.72 +
      + 30 + + 5,381.41 +
      + 31 + + 10,383.56 +
      + 32 + + 14,748.60 +
      + 33 + + 10,048.16 +
      + 34 + + 13,251.68 +
      + 35 + + 9,789.56 +
      + 36 + + 10,578.55 +
      + 37 + + 8,956.30 +
      + 38 + + 13,454.83 +
      + 39 + + 11,885.60 +
      + 40 + + 8,569.53 +
      + 41 + + 4,560.28 +
      + 42 + + 8,849.83 +
      + 43 + + 14,110.56 +
      + 44 + + 12,045.58 +
      + 45 + + 4,707.93 +
      + 46 + + 12,753.39 +
      + 47 + + 12,406.81 +
      + 48 + + 14,353.49 +
      + 49 + + 11,425.66 +
      + 50 + + 11,184.85 +
      + 51 + + 11,880.04 +
      + 52 + + 1,855.70 +
      + 1 + +   +
      + 2 + +   +
      + 3 + +   +
      + 4 + +   +
      + 5 + +   +
      + 6 + +   +
      + 7 + +   +
      + 8 + +   +
      + 9 + +   +
      + 10 + +   +
      + 11 + +   +
      + 12 + +   +
      + 13 + +   +
      + 14 + +   +
      + 15 + +   +
      + 16 + +   +
      + 17 + +   +
      + 18 + +   +
      + 19 + +   +
      + 20 + +   +
      + 21 + +   +
      + 22 + +   +
      + 23 + +   +
      + 24 + +   +
      + 25 + +   +
      + 26 + +   +
      + 27 + +   +
      + 28 + +   +
      + 29 + +   +
      + 30 + +   +
      + 31 + +   +
      + 32 + +   +
      + 33 + +   +
      + 34 + +   +
      + 35 + +   +
      + 36 + +   +
      + 37 + +   +
      + 38 + +   +
      + 39 + +   +
      + 40 + +   +
      + 41 + +   +
      + 42 + +   +
      + 43 + +   +
      + 44 + +   +
      + 45 + +   +
      + 46 + +   +
      + 47 + +   +
      + 48 + +   +
      + 49 + +   +
      + 50 + +   +
      + 51 + +   +
      + 52 + +   +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/single-dim-crossjoin-false-true-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/single-dim-crossjoin-false-true-true-result.html index fac25891..04e5e269 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/single-dim-crossjoin-false-true-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/single-dim-crossjoin-false-true-true-result.html @@ -1,878 +1,878 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      - Time - - Weekly - - Measures -
      - Year - - (All) - - Year - - Week - - Store Sales -
      - 1997 - - All Time.Weeklys - - 1997 - - 1 - - 11,734.43 -
      - 2 - - 19,756.43 -
      - 3 - - 19,933.22 -
      - 4 - - 10,640.96 -
      - 5 - - 12,339.06 -
      - 6 - - 5,485.97 -
      - 7 - - 11,368.84 -
      - 8 - - 12,762.95 -
      - 9 - - 11,095.62 -
      - 10 - - 9,205.40 -
      - 11 - - 7,775.74 -
      - 12 - - 13,083.95 -
      - 13 - - 18,164.50 -
      - 14 - - 9,086.91 -
      - 15 - - 9,534.01 -
      - 16 - - 8,099.97 -
      - 17 - - 14,361.15 -
      - 18 - - 8,055.59 -
      - 19 - - 10,046.38 -
      - 20 - - 14,158.00 -
      - 21 - - 9,629.54 -
      - 22 - - 8,962.98 -
      - 23 - - 5,178.50 -
      - 24 - - 11,371.84 -
      - 25 - - 6,601.20 -
      - 26 - - 16,382.53 -
      - 27 - - 9,821.26 -
      - 28 - - 12,408.58 -
      - 29 - - 11,010.72 -
      - 30 - - 5,381.41 -
      - 31 - - 10,383.56 -
      - 32 - - 14,748.60 -
      - 33 - - 10,048.16 -
      - 34 - - 13,251.68 -
      - 35 - - 9,789.56 -
      - 36 - - 10,578.55 -
      - 37 - - 8,956.30 -
      - 38 - - 13,454.83 -
      - 39 - - 11,885.60 -
      - 40 - - 8,569.53 -
      - 41 - - 4,560.28 -
      - 42 - - 8,849.83 -
      - 43 - - 14,110.56 -
      - 44 - - 12,045.58 -
      - 45 - - 4,707.93 -
      - 46 - - 12,753.39 -
      - 47 - - 12,406.81 -
      - 48 - - 14,353.49 -
      - 49 - - 11,425.66 -
      - 50 - - 11,184.85 -
      - 51 - - 11,880.04 -
      - 52 - - 1,855.70 -
      - 1998 - - 1 - -   -
      - 2 - -   -
      - 3 - -   -
      - 4 - -   -
      - 5 - -   -
      - 6 - -   -
      - 7 - -   -
      - 8 - -   -
      - 9 - -   -
      - 10 - -   -
      - 11 - -   -
      - 12 - -   -
      - 13 - -   -
      - 14 - -   -
      - 15 - -   -
      - 16 - -   -
      - 17 - -   -
      - 18 - -   -
      - 19 - -   -
      - 20 - -   -
      - 21 - -   -
      - 22 - -   -
      - 23 - -   -
      - 24 - -   -
      - 25 - -   -
      - 26 - -   -
      - 27 - -   -
      - 28 - -   -
      - 29 - -   -
      - 30 - -   -
      - 31 - -   -
      - 32 - -   -
      - 33 - -   -
      - 34 - -   -
      - 35 - -   -
      - 36 - -   -
      - 37 - -   -
      - 38 - -   -
      - 39 - -   -
      - 40 - -   -
      - 41 - -   -
      - 42 - -   -
      - 43 - -   -
      - 44 - -   -
      - 45 - -   -
      - 46 - -   -
      - 47 - -   -
      - 48 - -   -
      - 49 - -   -
      - 50 - -   -
      - 51 - -   -
      - 52 - -   -
      + Time + + Weekly + + Measures +
      + Year + + (All) + + Year + + Week + + Store Sales +
      + 1997 + + All Time.Weeklys + + 1997 + + 1 + + 11,734.43 +
      + 2 + + 19,756.43 +
      + 3 + + 19,933.22 +
      + 4 + + 10,640.96 +
      + 5 + + 12,339.06 +
      + 6 + + 5,485.97 +
      + 7 + + 11,368.84 +
      + 8 + + 12,762.95 +
      + 9 + + 11,095.62 +
      + 10 + + 9,205.40 +
      + 11 + + 7,775.74 +
      + 12 + + 13,083.95 +
      + 13 + + 18,164.50 +
      + 14 + + 9,086.91 +
      + 15 + + 9,534.01 +
      + 16 + + 8,099.97 +
      + 17 + + 14,361.15 +
      + 18 + + 8,055.59 +
      + 19 + + 10,046.38 +
      + 20 + + 14,158.00 +
      + 21 + + 9,629.54 +
      + 22 + + 8,962.98 +
      + 23 + + 5,178.50 +
      + 24 + + 11,371.84 +
      + 25 + + 6,601.20 +
      + 26 + + 16,382.53 +
      + 27 + + 9,821.26 +
      + 28 + + 12,408.58 +
      + 29 + + 11,010.72 +
      + 30 + + 5,381.41 +
      + 31 + + 10,383.56 +
      + 32 + + 14,748.60 +
      + 33 + + 10,048.16 +
      + 34 + + 13,251.68 +
      + 35 + + 9,789.56 +
      + 36 + + 10,578.55 +
      + 37 + + 8,956.30 +
      + 38 + + 13,454.83 +
      + 39 + + 11,885.60 +
      + 40 + + 8,569.53 +
      + 41 + + 4,560.28 +
      + 42 + + 8,849.83 +
      + 43 + + 14,110.56 +
      + 44 + + 12,045.58 +
      + 45 + + 4,707.93 +
      + 46 + + 12,753.39 +
      + 47 + + 12,406.81 +
      + 48 + + 14,353.49 +
      + 49 + + 11,425.66 +
      + 50 + + 11,184.85 +
      + 51 + + 11,880.04 +
      + 52 + + 1,855.70 +
      + 1998 + + 1 + +   +
      + 2 + +   +
      + 3 + +   +
      + 4 + +   +
      + 5 + +   +
      + 6 + +   +
      + 7 + +   +
      + 8 + +   +
      + 9 + +   +
      + 10 + +   +
      + 11 + +   +
      + 12 + +   +
      + 13 + +   +
      + 14 + +   +
      + 15 + +   +
      + 16 + +   +
      + 17 + +   +
      + 18 + +   +
      + 19 + +   +
      + 20 + +   +
      + 21 + +   +
      + 22 + +   +
      + 23 + +   +
      + 24 + +   +
      + 25 + +   +
      + 26 + +   +
      + 27 + +   +
      + 28 + +   +
      + 29 + +   +
      + 30 + +   +
      + 31 + +   +
      + 32 + +   +
      + 33 + +   +
      + 34 + +   +
      + 35 + +   +
      + 36 + +   +
      + 37 + +   +
      + 38 + +   +
      + 39 + +   +
      + 40 + +   +
      + 41 + +   +
      + 42 + +   +
      + 43 + +   +
      + 44 + +   +
      + 45 + +   +
      + 46 + +   +
      + 47 + +   +
      + 48 + +   +
      + 49 + +   +
      + 50 + +   +
      + 51 + +   +
      + 52 + +   +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/single-dim-crossjoin-true-false-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/single-dim-crossjoin-true-false-false-result.html index 741f2457..10f876b4 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/single-dim-crossjoin-true-false-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/single-dim-crossjoin-true-false-false-result.html @@ -1,1158 +1,1158 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Store Sales -
      - 1997 - - 1 - - 11,734.43 -
      - 1997 - - 2 - - 19,756.43 -
      - 1997 - - 3 - - 19,933.22 -
      - 1997 - - 4 - - 10,640.96 -
      - 1997 - - 5 - - 12,339.06 -
      - 1997 - - 6 - - 5,485.97 -
      - 1997 - - 7 - - 11,368.84 -
      - 1997 - - 8 - - 12,762.95 -
      - 1997 - - 9 - - 11,095.62 -
      - 1997 - - 10 - - 9,205.40 -
      - 1997 - - 11 - - 7,775.74 -
      - 1997 - - 12 - - 13,083.95 -
      - 1997 - - 13 - - 18,164.50 -
      - 1997 - - 14 - - 9,086.91 -
      - 1997 - - 15 - - 9,534.01 -
      - 1997 - - 16 - - 8,099.97 -
      - 1997 - - 17 - - 14,361.15 -
      - 1997 - - 18 - - 8,055.59 -
      - 1997 - - 19 - - 10,046.38 -
      - 1997 - - 20 - - 14,158.00 -
      - 1997 - - 21 - - 9,629.54 -
      - 1997 - - 22 - - 8,962.98 -
      - 1997 - - 23 - - 5,178.50 -
      - 1997 - - 24 - - 11,371.84 -
      - 1997 - - 25 - - 6,601.20 -
      - 1997 - - 26 - - 16,382.53 -
      - 1997 - - 27 - - 9,821.26 -
      - 1997 - - 28 - - 12,408.58 -
      - 1997 - - 29 - - 11,010.72 -
      - 1997 - - 30 - - 5,381.41 -
      - 1997 - - 31 - - 10,383.56 -
      - 1997 - - 32 - - 14,748.60 -
      - 1997 - - 33 - - 10,048.16 -
      - 1997 - - 34 - - 13,251.68 -
      - 1997 - - 35 - - 9,789.56 -
      - 1997 - - 36 - - 10,578.55 -
      - 1997 - - 37 - - 8,956.30 -
      - 1997 - - 38 - - 13,454.83 -
      - 1997 - - 39 - - 11,885.60 -
      - 1997 - - 40 - - 8,569.53 -
      - 1997 - - 41 - - 4,560.28 -
      - 1997 - - 42 - - 8,849.83 -
      - 1997 - - 43 - - 14,110.56 -
      - 1997 - - 44 - - 12,045.58 -
      - 1997 - - 45 - - 4,707.93 -
      - 1997 - - 46 - - 12,753.39 -
      - 1997 - - 47 - - 12,406.81 -
      - 1997 - - 48 - - 14,353.49 -
      - 1997 - - 49 - - 11,425.66 -
      - 1997 - - 50 - - 11,184.85 -
      - 1997 - - 51 - - 11,880.04 -
      - 1997 - - 52 - - 1,855.70 -
      - 1997 - - 1 - -   -
      - 1997 - - 2 - -   -
      - 1997 - - 3 - -   -
      - 1997 - - 4 - -   -
      - 1997 - - 5 - -   -
      - 1997 - - 6 - -   -
      - 1997 - - 7 - -   -
      - 1997 - - 8 - -   -
      - 1997 - - 9 - -   -
      - 1997 - - 10 - -   -
      - 1997 - - 11 - -   -
      - 1997 - - 12 - -   -
      - 1997 - - 13 - -   -
      - 1997 - - 14 - -   -
      - 1997 - - 15 - -   -
      - 1997 - - 16 - -   -
      - 1997 - - 17 - -   -
      - 1997 - - 18 - -   -
      - 1997 - - 19 - -   -
      - 1997 - - 20 - -   -
      - 1997 - - 21 - -   -
      - 1997 - - 22 - -   -
      - 1997 - - 23 - -   -
      - 1997 - - 24 - -   -
      - 1997 - - 25 - -   -
      - 1997 - - 26 - -   -
      - 1997 - - 27 - -   -
      - 1997 - - 28 - -   -
      - 1997 - - 29 - -   -
      - 1997 - - 30 - -   -
      - 1997 - - 31 - -   -
      - 1997 - - 32 - -   -
      - 1997 - - 33 - -   -
      - 1997 - - 34 - -   -
      - 1997 - - 35 - -   -
      - 1997 - - 36 - -   -
      - 1997 - - 37 - -   -
      - 1997 - - 38 - -   -
      - 1997 - - 39 - -   -
      - 1997 - - 40 - -   -
      - 1997 - - 41 - -   -
      - 1997 - - 42 - -   -
      - 1997 - - 43 - -   -
      - 1997 - - 44 - -   -
      - 1997 - - 45 - -   -
      - 1997 - - 46 - -   -
      - 1997 - - 47 - -   -
      - 1997 - - 48 - -   -
      - 1997 - - 49 - -   -
      - 1997 - - 50 - -   -
      - 1997 - - 51 - -   -
      - 1997 - - 52 - -   -
      +   + + Store Sales +
      + 1997 + + 1 + + 11,734.43 +
      + 1997 + + 2 + + 19,756.43 +
      + 1997 + + 3 + + 19,933.22 +
      + 1997 + + 4 + + 10,640.96 +
      + 1997 + + 5 + + 12,339.06 +
      + 1997 + + 6 + + 5,485.97 +
      + 1997 + + 7 + + 11,368.84 +
      + 1997 + + 8 + + 12,762.95 +
      + 1997 + + 9 + + 11,095.62 +
      + 1997 + + 10 + + 9,205.40 +
      + 1997 + + 11 + + 7,775.74 +
      + 1997 + + 12 + + 13,083.95 +
      + 1997 + + 13 + + 18,164.50 +
      + 1997 + + 14 + + 9,086.91 +
      + 1997 + + 15 + + 9,534.01 +
      + 1997 + + 16 + + 8,099.97 +
      + 1997 + + 17 + + 14,361.15 +
      + 1997 + + 18 + + 8,055.59 +
      + 1997 + + 19 + + 10,046.38 +
      + 1997 + + 20 + + 14,158.00 +
      + 1997 + + 21 + + 9,629.54 +
      + 1997 + + 22 + + 8,962.98 +
      + 1997 + + 23 + + 5,178.50 +
      + 1997 + + 24 + + 11,371.84 +
      + 1997 + + 25 + + 6,601.20 +
      + 1997 + + 26 + + 16,382.53 +
      + 1997 + + 27 + + 9,821.26 +
      + 1997 + + 28 + + 12,408.58 +
      + 1997 + + 29 + + 11,010.72 +
      + 1997 + + 30 + + 5,381.41 +
      + 1997 + + 31 + + 10,383.56 +
      + 1997 + + 32 + + 14,748.60 +
      + 1997 + + 33 + + 10,048.16 +
      + 1997 + + 34 + + 13,251.68 +
      + 1997 + + 35 + + 9,789.56 +
      + 1997 + + 36 + + 10,578.55 +
      + 1997 + + 37 + + 8,956.30 +
      + 1997 + + 38 + + 13,454.83 +
      + 1997 + + 39 + + 11,885.60 +
      + 1997 + + 40 + + 8,569.53 +
      + 1997 + + 41 + + 4,560.28 +
      + 1997 + + 42 + + 8,849.83 +
      + 1997 + + 43 + + 14,110.56 +
      + 1997 + + 44 + + 12,045.58 +
      + 1997 + + 45 + + 4,707.93 +
      + 1997 + + 46 + + 12,753.39 +
      + 1997 + + 47 + + 12,406.81 +
      + 1997 + + 48 + + 14,353.49 +
      + 1997 + + 49 + + 11,425.66 +
      + 1997 + + 50 + + 11,184.85 +
      + 1997 + + 51 + + 11,880.04 +
      + 1997 + + 52 + + 1,855.70 +
      + 1997 + + 1 + +   +
      + 1997 + + 2 + +   +
      + 1997 + + 3 + +   +
      + 1997 + + 4 + +   +
      + 1997 + + 5 + +   +
      + 1997 + + 6 + +   +
      + 1997 + + 7 + +   +
      + 1997 + + 8 + +   +
      + 1997 + + 9 + +   +
      + 1997 + + 10 + +   +
      + 1997 + + 11 + +   +
      + 1997 + + 12 + +   +
      + 1997 + + 13 + +   +
      + 1997 + + 14 + +   +
      + 1997 + + 15 + +   +
      + 1997 + + 16 + +   +
      + 1997 + + 17 + +   +
      + 1997 + + 18 + +   +
      + 1997 + + 19 + +   +
      + 1997 + + 20 + +   +
      + 1997 + + 21 + +   +
      + 1997 + + 22 + +   +
      + 1997 + + 23 + +   +
      + 1997 + + 24 + +   +
      + 1997 + + 25 + +   +
      + 1997 + + 26 + +   +
      + 1997 + + 27 + +   +
      + 1997 + + 28 + +   +
      + 1997 + + 29 + +   +
      + 1997 + + 30 + +   +
      + 1997 + + 31 + +   +
      + 1997 + + 32 + +   +
      + 1997 + + 33 + +   +
      + 1997 + + 34 + +   +
      + 1997 + + 35 + +   +
      + 1997 + + 36 + +   +
      + 1997 + + 37 + +   +
      + 1997 + + 38 + +   +
      + 1997 + + 39 + +   +
      + 1997 + + 40 + +   +
      + 1997 + + 41 + +   +
      + 1997 + + 42 + +   +
      + 1997 + + 43 + +   +
      + 1997 + + 44 + +   +
      + 1997 + + 45 + +   +
      + 1997 + + 46 + +   +
      + 1997 + + 47 + +   +
      + 1997 + + 48 + +   +
      + 1997 + + 49 + +   +
      + 1997 + + 50 + +   +
      + 1997 + + 51 + +   +
      + 1997 + + 52 + +   +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/single-dim-crossjoin-true-false-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/single-dim-crossjoin-true-false-true-result.html index 93102aef..81f5f044 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/single-dim-crossjoin-true-false-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/single-dim-crossjoin-true-false-true-result.html @@ -1,1782 +1,1782 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Store Sales -
      - 1997 - - All Time.Weeklys - - 1997 - - 1 - - 11,734.43 -
      - 1997 - - All Time.Weeklys - - 1997 - - 2 - - 19,756.43 -
      - 1997 - - All Time.Weeklys - - 1997 - - 3 - - 19,933.22 -
      - 1997 - - All Time.Weeklys - - 1997 - - 4 - - 10,640.96 -
      - 1997 - - All Time.Weeklys - - 1997 - - 5 - - 12,339.06 -
      - 1997 - - All Time.Weeklys - - 1997 - - 6 - - 5,485.97 -
      - 1997 - - All Time.Weeklys - - 1997 - - 7 - - 11,368.84 -
      - 1997 - - All Time.Weeklys - - 1997 - - 8 - - 12,762.95 -
      - 1997 - - All Time.Weeklys - - 1997 - - 9 - - 11,095.62 -
      - 1997 - - All Time.Weeklys - - 1997 - - 10 - - 9,205.40 -
      - 1997 - - All Time.Weeklys - - 1997 - - 11 - - 7,775.74 -
      - 1997 - - All Time.Weeklys - - 1997 - - 12 - - 13,083.95 -
      - 1997 - - All Time.Weeklys - - 1997 - - 13 - - 18,164.50 -
      - 1997 - - All Time.Weeklys - - 1997 - - 14 - - 9,086.91 -
      - 1997 - - All Time.Weeklys - - 1997 - - 15 - - 9,534.01 -
      - 1997 - - All Time.Weeklys - - 1997 - - 16 - - 8,099.97 -
      - 1997 - - All Time.Weeklys - - 1997 - - 17 - - 14,361.15 -
      - 1997 - - All Time.Weeklys - - 1997 - - 18 - - 8,055.59 -
      - 1997 - - All Time.Weeklys - - 1997 - - 19 - - 10,046.38 -
      - 1997 - - All Time.Weeklys - - 1997 - - 20 - - 14,158.00 -
      - 1997 - - All Time.Weeklys - - 1997 - - 21 - - 9,629.54 -
      - 1997 - - All Time.Weeklys - - 1997 - - 22 - - 8,962.98 -
      - 1997 - - All Time.Weeklys - - 1997 - - 23 - - 5,178.50 -
      - 1997 - - All Time.Weeklys - - 1997 - - 24 - - 11,371.84 -
      - 1997 - - All Time.Weeklys - - 1997 - - 25 - - 6,601.20 -
      - 1997 - - All Time.Weeklys - - 1997 - - 26 - - 16,382.53 -
      - 1997 - - All Time.Weeklys - - 1997 - - 27 - - 9,821.26 -
      - 1997 - - All Time.Weeklys - - 1997 - - 28 - - 12,408.58 -
      - 1997 - - All Time.Weeklys - - 1997 - - 29 - - 11,010.72 -
      - 1997 - - All Time.Weeklys - - 1997 - - 30 - - 5,381.41 -
      - 1997 - - All Time.Weeklys - - 1997 - - 31 - - 10,383.56 -
      - 1997 - - All Time.Weeklys - - 1997 - - 32 - - 14,748.60 -
      - 1997 - - All Time.Weeklys - - 1997 - - 33 - - 10,048.16 -
      - 1997 - - All Time.Weeklys - - 1997 - - 34 - - 13,251.68 -
      - 1997 - - All Time.Weeklys - - 1997 - - 35 - - 9,789.56 -
      - 1997 - - All Time.Weeklys - - 1997 - - 36 - - 10,578.55 -
      - 1997 - - All Time.Weeklys - - 1997 - - 37 - - 8,956.30 -
      - 1997 - - All Time.Weeklys - - 1997 - - 38 - - 13,454.83 -
      - 1997 - - All Time.Weeklys - - 1997 - - 39 - - 11,885.60 -
      - 1997 - - All Time.Weeklys - - 1997 - - 40 - - 8,569.53 -
      - 1997 - - All Time.Weeklys - - 1997 - - 41 - - 4,560.28 -
      - 1997 - - All Time.Weeklys - - 1997 - - 42 - - 8,849.83 -
      - 1997 - - All Time.Weeklys - - 1997 - - 43 - - 14,110.56 -
      - 1997 - - All Time.Weeklys - - 1997 - - 44 - - 12,045.58 -
      - 1997 - - All Time.Weeklys - - 1997 - - 45 - - 4,707.93 -
      - 1997 - - All Time.Weeklys - - 1997 - - 46 - - 12,753.39 -
      - 1997 - - All Time.Weeklys - - 1997 - - 47 - - 12,406.81 -
      - 1997 - - All Time.Weeklys - - 1997 - - 48 - - 14,353.49 -
      - 1997 - - All Time.Weeklys - - 1997 - - 49 - - 11,425.66 -
      - 1997 - - All Time.Weeklys - - 1997 - - 50 - - 11,184.85 -
      - 1997 - - All Time.Weeklys - - 1997 - - 51 - - 11,880.04 -
      - 1997 - - All Time.Weeklys - - 1997 - - 52 - - 1,855.70 -
      - 1997 - - All Time.Weeklys - - 1998 - - 1 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 2 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 3 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 4 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 5 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 6 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 7 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 8 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 9 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 10 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 11 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 12 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 13 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 14 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 15 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 16 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 17 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 18 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 19 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 20 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 21 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 22 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 23 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 24 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 25 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 26 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 27 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 28 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 29 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 30 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 31 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 32 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 33 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 34 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 35 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 36 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 37 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 38 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 39 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 40 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 41 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 42 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 43 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 44 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 45 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 46 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 47 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 48 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 49 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 50 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 51 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 52 - -   -
      +   + + Store Sales +
      + 1997 + + All Time.Weeklys + + 1997 + + 1 + + 11,734.43 +
      + 1997 + + All Time.Weeklys + + 1997 + + 2 + + 19,756.43 +
      + 1997 + + All Time.Weeklys + + 1997 + + 3 + + 19,933.22 +
      + 1997 + + All Time.Weeklys + + 1997 + + 4 + + 10,640.96 +
      + 1997 + + All Time.Weeklys + + 1997 + + 5 + + 12,339.06 +
      + 1997 + + All Time.Weeklys + + 1997 + + 6 + + 5,485.97 +
      + 1997 + + All Time.Weeklys + + 1997 + + 7 + + 11,368.84 +
      + 1997 + + All Time.Weeklys + + 1997 + + 8 + + 12,762.95 +
      + 1997 + + All Time.Weeklys + + 1997 + + 9 + + 11,095.62 +
      + 1997 + + All Time.Weeklys + + 1997 + + 10 + + 9,205.40 +
      + 1997 + + All Time.Weeklys + + 1997 + + 11 + + 7,775.74 +
      + 1997 + + All Time.Weeklys + + 1997 + + 12 + + 13,083.95 +
      + 1997 + + All Time.Weeklys + + 1997 + + 13 + + 18,164.50 +
      + 1997 + + All Time.Weeklys + + 1997 + + 14 + + 9,086.91 +
      + 1997 + + All Time.Weeklys + + 1997 + + 15 + + 9,534.01 +
      + 1997 + + All Time.Weeklys + + 1997 + + 16 + + 8,099.97 +
      + 1997 + + All Time.Weeklys + + 1997 + + 17 + + 14,361.15 +
      + 1997 + + All Time.Weeklys + + 1997 + + 18 + + 8,055.59 +
      + 1997 + + All Time.Weeklys + + 1997 + + 19 + + 10,046.38 +
      + 1997 + + All Time.Weeklys + + 1997 + + 20 + + 14,158.00 +
      + 1997 + + All Time.Weeklys + + 1997 + + 21 + + 9,629.54 +
      + 1997 + + All Time.Weeklys + + 1997 + + 22 + + 8,962.98 +
      + 1997 + + All Time.Weeklys + + 1997 + + 23 + + 5,178.50 +
      + 1997 + + All Time.Weeklys + + 1997 + + 24 + + 11,371.84 +
      + 1997 + + All Time.Weeklys + + 1997 + + 25 + + 6,601.20 +
      + 1997 + + All Time.Weeklys + + 1997 + + 26 + + 16,382.53 +
      + 1997 + + All Time.Weeklys + + 1997 + + 27 + + 9,821.26 +
      + 1997 + + All Time.Weeklys + + 1997 + + 28 + + 12,408.58 +
      + 1997 + + All Time.Weeklys + + 1997 + + 29 + + 11,010.72 +
      + 1997 + + All Time.Weeklys + + 1997 + + 30 + + 5,381.41 +
      + 1997 + + All Time.Weeklys + + 1997 + + 31 + + 10,383.56 +
      + 1997 + + All Time.Weeklys + + 1997 + + 32 + + 14,748.60 +
      + 1997 + + All Time.Weeklys + + 1997 + + 33 + + 10,048.16 +
      + 1997 + + All Time.Weeklys + + 1997 + + 34 + + 13,251.68 +
      + 1997 + + All Time.Weeklys + + 1997 + + 35 + + 9,789.56 +
      + 1997 + + All Time.Weeklys + + 1997 + + 36 + + 10,578.55 +
      + 1997 + + All Time.Weeklys + + 1997 + + 37 + + 8,956.30 +
      + 1997 + + All Time.Weeklys + + 1997 + + 38 + + 13,454.83 +
      + 1997 + + All Time.Weeklys + + 1997 + + 39 + + 11,885.60 +
      + 1997 + + All Time.Weeklys + + 1997 + + 40 + + 8,569.53 +
      + 1997 + + All Time.Weeklys + + 1997 + + 41 + + 4,560.28 +
      + 1997 + + All Time.Weeklys + + 1997 + + 42 + + 8,849.83 +
      + 1997 + + All Time.Weeklys + + 1997 + + 43 + + 14,110.56 +
      + 1997 + + All Time.Weeklys + + 1997 + + 44 + + 12,045.58 +
      + 1997 + + All Time.Weeklys + + 1997 + + 45 + + 4,707.93 +
      + 1997 + + All Time.Weeklys + + 1997 + + 46 + + 12,753.39 +
      + 1997 + + All Time.Weeklys + + 1997 + + 47 + + 12,406.81 +
      + 1997 + + All Time.Weeklys + + 1997 + + 48 + + 14,353.49 +
      + 1997 + + All Time.Weeklys + + 1997 + + 49 + + 11,425.66 +
      + 1997 + + All Time.Weeklys + + 1997 + + 50 + + 11,184.85 +
      + 1997 + + All Time.Weeklys + + 1997 + + 51 + + 11,880.04 +
      + 1997 + + All Time.Weeklys + + 1997 + + 52 + + 1,855.70 +
      + 1997 + + All Time.Weeklys + + 1998 + + 1 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 2 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 3 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 4 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 5 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 6 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 7 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 8 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 9 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 10 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 11 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 12 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 13 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 14 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 15 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 16 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 17 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 18 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 19 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 20 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 21 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 22 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 23 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 24 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 25 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 26 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 27 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 28 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 29 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 30 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 31 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 32 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 33 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 34 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 35 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 36 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 37 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 38 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 39 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 40 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 41 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 42 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 43 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 44 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 45 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 46 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 47 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 48 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 49 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 50 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 51 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 52 + +   +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/single-dim-crossjoin-true-true-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/single-dim-crossjoin-true-true-false-result.html index ab8a3781..b39011d2 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/single-dim-crossjoin-true-true-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/single-dim-crossjoin-true-true-false-result.html @@ -1,1169 +1,1169 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Measures -
      - Time - - Weekly - - Store Sales -
      - 1997 - - 1 - - 11,734.43 -
      - 1997 - - 2 - - 19,756.43 -
      - 1997 - - 3 - - 19,933.22 -
      - 1997 - - 4 - - 10,640.96 -
      - 1997 - - 5 - - 12,339.06 -
      - 1997 - - 6 - - 5,485.97 -
      - 1997 - - 7 - - 11,368.84 -
      - 1997 - - 8 - - 12,762.95 -
      - 1997 - - 9 - - 11,095.62 -
      - 1997 - - 10 - - 9,205.40 -
      - 1997 - - 11 - - 7,775.74 -
      - 1997 - - 12 - - 13,083.95 -
      - 1997 - - 13 - - 18,164.50 -
      - 1997 - - 14 - - 9,086.91 -
      - 1997 - - 15 - - 9,534.01 -
      - 1997 - - 16 - - 8,099.97 -
      - 1997 - - 17 - - 14,361.15 -
      - 1997 - - 18 - - 8,055.59 -
      - 1997 - - 19 - - 10,046.38 -
      - 1997 - - 20 - - 14,158.00 -
      - 1997 - - 21 - - 9,629.54 -
      - 1997 - - 22 - - 8,962.98 -
      - 1997 - - 23 - - 5,178.50 -
      - 1997 - - 24 - - 11,371.84 -
      - 1997 - - 25 - - 6,601.20 -
      - 1997 - - 26 - - 16,382.53 -
      - 1997 - - 27 - - 9,821.26 -
      - 1997 - - 28 - - 12,408.58 -
      - 1997 - - 29 - - 11,010.72 -
      - 1997 - - 30 - - 5,381.41 -
      - 1997 - - 31 - - 10,383.56 -
      - 1997 - - 32 - - 14,748.60 -
      - 1997 - - 33 - - 10,048.16 -
      - 1997 - - 34 - - 13,251.68 -
      - 1997 - - 35 - - 9,789.56 -
      - 1997 - - 36 - - 10,578.55 -
      - 1997 - - 37 - - 8,956.30 -
      - 1997 - - 38 - - 13,454.83 -
      - 1997 - - 39 - - 11,885.60 -
      - 1997 - - 40 - - 8,569.53 -
      - 1997 - - 41 - - 4,560.28 -
      - 1997 - - 42 - - 8,849.83 -
      - 1997 - - 43 - - 14,110.56 -
      - 1997 - - 44 - - 12,045.58 -
      - 1997 - - 45 - - 4,707.93 -
      - 1997 - - 46 - - 12,753.39 -
      - 1997 - - 47 - - 12,406.81 -
      - 1997 - - 48 - - 14,353.49 -
      - 1997 - - 49 - - 11,425.66 -
      - 1997 - - 50 - - 11,184.85 -
      - 1997 - - 51 - - 11,880.04 -
      - 1997 - - 52 - - 1,855.70 -
      - 1997 - - 1 - -   -
      - 1997 - - 2 - -   -
      - 1997 - - 3 - -   -
      - 1997 - - 4 - -   -
      - 1997 - - 5 - -   -
      - 1997 - - 6 - -   -
      - 1997 - - 7 - -   -
      - 1997 - - 8 - -   -
      - 1997 - - 9 - -   -
      - 1997 - - 10 - -   -
      - 1997 - - 11 - -   -
      - 1997 - - 12 - -   -
      - 1997 - - 13 - -   -
      - 1997 - - 14 - -   -
      - 1997 - - 15 - -   -
      - 1997 - - 16 - -   -
      - 1997 - - 17 - -   -
      - 1997 - - 18 - -   -
      - 1997 - - 19 - -   -
      - 1997 - - 20 - -   -
      - 1997 - - 21 - -   -
      - 1997 - - 22 - -   -
      - 1997 - - 23 - -   -
      - 1997 - - 24 - -   -
      - 1997 - - 25 - -   -
      - 1997 - - 26 - -   -
      - 1997 - - 27 - -   -
      - 1997 - - 28 - -   -
      - 1997 - - 29 - -   -
      - 1997 - - 30 - -   -
      - 1997 - - 31 - -   -
      - 1997 - - 32 - -   -
      - 1997 - - 33 - -   -
      - 1997 - - 34 - -   -
      - 1997 - - 35 - -   -
      - 1997 - - 36 - -   -
      - 1997 - - 37 - -   -
      - 1997 - - 38 - -   -
      - 1997 - - 39 - -   -
      - 1997 - - 40 - -   -
      - 1997 - - 41 - -   -
      - 1997 - - 42 - -   -
      - 1997 - - 43 - -   -
      - 1997 - - 44 - -   -
      - 1997 - - 45 - -   -
      - 1997 - - 46 - -   -
      - 1997 - - 47 - -   -
      - 1997 - - 48 - -   -
      - 1997 - - 49 - -   -
      - 1997 - - 50 - -   -
      - 1997 - - 51 - -   -
      - 1997 - - 52 - -   -
      +   + + Measures +
      + Time + + Weekly + + Store Sales +
      + 1997 + + 1 + + 11,734.43 +
      + 1997 + + 2 + + 19,756.43 +
      + 1997 + + 3 + + 19,933.22 +
      + 1997 + + 4 + + 10,640.96 +
      + 1997 + + 5 + + 12,339.06 +
      + 1997 + + 6 + + 5,485.97 +
      + 1997 + + 7 + + 11,368.84 +
      + 1997 + + 8 + + 12,762.95 +
      + 1997 + + 9 + + 11,095.62 +
      + 1997 + + 10 + + 9,205.40 +
      + 1997 + + 11 + + 7,775.74 +
      + 1997 + + 12 + + 13,083.95 +
      + 1997 + + 13 + + 18,164.50 +
      + 1997 + + 14 + + 9,086.91 +
      + 1997 + + 15 + + 9,534.01 +
      + 1997 + + 16 + + 8,099.97 +
      + 1997 + + 17 + + 14,361.15 +
      + 1997 + + 18 + + 8,055.59 +
      + 1997 + + 19 + + 10,046.38 +
      + 1997 + + 20 + + 14,158.00 +
      + 1997 + + 21 + + 9,629.54 +
      + 1997 + + 22 + + 8,962.98 +
      + 1997 + + 23 + + 5,178.50 +
      + 1997 + + 24 + + 11,371.84 +
      + 1997 + + 25 + + 6,601.20 +
      + 1997 + + 26 + + 16,382.53 +
      + 1997 + + 27 + + 9,821.26 +
      + 1997 + + 28 + + 12,408.58 +
      + 1997 + + 29 + + 11,010.72 +
      + 1997 + + 30 + + 5,381.41 +
      + 1997 + + 31 + + 10,383.56 +
      + 1997 + + 32 + + 14,748.60 +
      + 1997 + + 33 + + 10,048.16 +
      + 1997 + + 34 + + 13,251.68 +
      + 1997 + + 35 + + 9,789.56 +
      + 1997 + + 36 + + 10,578.55 +
      + 1997 + + 37 + + 8,956.30 +
      + 1997 + + 38 + + 13,454.83 +
      + 1997 + + 39 + + 11,885.60 +
      + 1997 + + 40 + + 8,569.53 +
      + 1997 + + 41 + + 4,560.28 +
      + 1997 + + 42 + + 8,849.83 +
      + 1997 + + 43 + + 14,110.56 +
      + 1997 + + 44 + + 12,045.58 +
      + 1997 + + 45 + + 4,707.93 +
      + 1997 + + 46 + + 12,753.39 +
      + 1997 + + 47 + + 12,406.81 +
      + 1997 + + 48 + + 14,353.49 +
      + 1997 + + 49 + + 11,425.66 +
      + 1997 + + 50 + + 11,184.85 +
      + 1997 + + 51 + + 11,880.04 +
      + 1997 + + 52 + + 1,855.70 +
      + 1997 + + 1 + +   +
      + 1997 + + 2 + +   +
      + 1997 + + 3 + +   +
      + 1997 + + 4 + +   +
      + 1997 + + 5 + +   +
      + 1997 + + 6 + +   +
      + 1997 + + 7 + +   +
      + 1997 + + 8 + +   +
      + 1997 + + 9 + +   +
      + 1997 + + 10 + +   +
      + 1997 + + 11 + +   +
      + 1997 + + 12 + +   +
      + 1997 + + 13 + +   +
      + 1997 + + 14 + +   +
      + 1997 + + 15 + +   +
      + 1997 + + 16 + +   +
      + 1997 + + 17 + +   +
      + 1997 + + 18 + +   +
      + 1997 + + 19 + +   +
      + 1997 + + 20 + +   +
      + 1997 + + 21 + +   +
      + 1997 + + 22 + +   +
      + 1997 + + 23 + +   +
      + 1997 + + 24 + +   +
      + 1997 + + 25 + +   +
      + 1997 + + 26 + +   +
      + 1997 + + 27 + +   +
      + 1997 + + 28 + +   +
      + 1997 + + 29 + +   +
      + 1997 + + 30 + +   +
      + 1997 + + 31 + +   +
      + 1997 + + 32 + +   +
      + 1997 + + 33 + +   +
      + 1997 + + 34 + +   +
      + 1997 + + 35 + +   +
      + 1997 + + 36 + +   +
      + 1997 + + 37 + +   +
      + 1997 + + 38 + +   +
      + 1997 + + 39 + +   +
      + 1997 + + 40 + +   +
      + 1997 + + 41 + +   +
      + 1997 + + 42 + +   +
      + 1997 + + 43 + +   +
      + 1997 + + 44 + +   +
      + 1997 + + 45 + +   +
      + 1997 + + 46 + +   +
      + 1997 + + 47 + +   +
      + 1997 + + 48 + +   +
      + 1997 + + 49 + +   +
      + 1997 + + 50 + +   +
      + 1997 + + 51 + +   +
      + 1997 + + 52 + +   +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/single-dim-crossjoin-true-true-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/single-dim-crossjoin-true-true-true-result.html index 2067ce23..a2dc0e54 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/single-dim-crossjoin-true-true-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/single-dim-crossjoin-true-true-true-result.html @@ -1,1802 +1,1802 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      - Time - - Weekly - - Measures -
      - Year - - (All) - - Year - - Week - - Store Sales -
      - 1997 - - All Time.Weeklys - - 1997 - - 1 - - 11,734.43 -
      - 1997 - - All Time.Weeklys - - 1997 - - 2 - - 19,756.43 -
      - 1997 - - All Time.Weeklys - - 1997 - - 3 - - 19,933.22 -
      - 1997 - - All Time.Weeklys - - 1997 - - 4 - - 10,640.96 -
      - 1997 - - All Time.Weeklys - - 1997 - - 5 - - 12,339.06 -
      - 1997 - - All Time.Weeklys - - 1997 - - 6 - - 5,485.97 -
      - 1997 - - All Time.Weeklys - - 1997 - - 7 - - 11,368.84 -
      - 1997 - - All Time.Weeklys - - 1997 - - 8 - - 12,762.95 -
      - 1997 - - All Time.Weeklys - - 1997 - - 9 - - 11,095.62 -
      - 1997 - - All Time.Weeklys - - 1997 - - 10 - - 9,205.40 -
      - 1997 - - All Time.Weeklys - - 1997 - - 11 - - 7,775.74 -
      - 1997 - - All Time.Weeklys - - 1997 - - 12 - - 13,083.95 -
      - 1997 - - All Time.Weeklys - - 1997 - - 13 - - 18,164.50 -
      - 1997 - - All Time.Weeklys - - 1997 - - 14 - - 9,086.91 -
      - 1997 - - All Time.Weeklys - - 1997 - - 15 - - 9,534.01 -
      - 1997 - - All Time.Weeklys - - 1997 - - 16 - - 8,099.97 -
      - 1997 - - All Time.Weeklys - - 1997 - - 17 - - 14,361.15 -
      - 1997 - - All Time.Weeklys - - 1997 - - 18 - - 8,055.59 -
      - 1997 - - All Time.Weeklys - - 1997 - - 19 - - 10,046.38 -
      - 1997 - - All Time.Weeklys - - 1997 - - 20 - - 14,158.00 -
      - 1997 - - All Time.Weeklys - - 1997 - - 21 - - 9,629.54 -
      - 1997 - - All Time.Weeklys - - 1997 - - 22 - - 8,962.98 -
      - 1997 - - All Time.Weeklys - - 1997 - - 23 - - 5,178.50 -
      - 1997 - - All Time.Weeklys - - 1997 - - 24 - - 11,371.84 -
      - 1997 - - All Time.Weeklys - - 1997 - - 25 - - 6,601.20 -
      - 1997 - - All Time.Weeklys - - 1997 - - 26 - - 16,382.53 -
      - 1997 - - All Time.Weeklys - - 1997 - - 27 - - 9,821.26 -
      - 1997 - - All Time.Weeklys - - 1997 - - 28 - - 12,408.58 -
      - 1997 - - All Time.Weeklys - - 1997 - - 29 - - 11,010.72 -
      - 1997 - - All Time.Weeklys - - 1997 - - 30 - - 5,381.41 -
      - 1997 - - All Time.Weeklys - - 1997 - - 31 - - 10,383.56 -
      - 1997 - - All Time.Weeklys - - 1997 - - 32 - - 14,748.60 -
      - 1997 - - All Time.Weeklys - - 1997 - - 33 - - 10,048.16 -
      - 1997 - - All Time.Weeklys - - 1997 - - 34 - - 13,251.68 -
      - 1997 - - All Time.Weeklys - - 1997 - - 35 - - 9,789.56 -
      - 1997 - - All Time.Weeklys - - 1997 - - 36 - - 10,578.55 -
      - 1997 - - All Time.Weeklys - - 1997 - - 37 - - 8,956.30 -
      - 1997 - - All Time.Weeklys - - 1997 - - 38 - - 13,454.83 -
      - 1997 - - All Time.Weeklys - - 1997 - - 39 - - 11,885.60 -
      - 1997 - - All Time.Weeklys - - 1997 - - 40 - - 8,569.53 -
      - 1997 - - All Time.Weeklys - - 1997 - - 41 - - 4,560.28 -
      - 1997 - - All Time.Weeklys - - 1997 - - 42 - - 8,849.83 -
      - 1997 - - All Time.Weeklys - - 1997 - - 43 - - 14,110.56 -
      - 1997 - - All Time.Weeklys - - 1997 - - 44 - - 12,045.58 -
      - 1997 - - All Time.Weeklys - - 1997 - - 45 - - 4,707.93 -
      - 1997 - - All Time.Weeklys - - 1997 - - 46 - - 12,753.39 -
      - 1997 - - All Time.Weeklys - - 1997 - - 47 - - 12,406.81 -
      - 1997 - - All Time.Weeklys - - 1997 - - 48 - - 14,353.49 -
      - 1997 - - All Time.Weeklys - - 1997 - - 49 - - 11,425.66 -
      - 1997 - - All Time.Weeklys - - 1997 - - 50 - - 11,184.85 -
      - 1997 - - All Time.Weeklys - - 1997 - - 51 - - 11,880.04 -
      - 1997 - - All Time.Weeklys - - 1997 - - 52 - - 1,855.70 -
      - 1997 - - All Time.Weeklys - - 1998 - - 1 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 2 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 3 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 4 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 5 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 6 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 7 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 8 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 9 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 10 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 11 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 12 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 13 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 14 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 15 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 16 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 17 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 18 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 19 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 20 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 21 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 22 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 23 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 24 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 25 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 26 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 27 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 28 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 29 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 30 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 31 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 32 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 33 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 34 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 35 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 36 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 37 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 38 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 39 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 40 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 41 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 42 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 43 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 44 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 45 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 46 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 47 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 48 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 49 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 50 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 51 - -   -
      - 1997 - - All Time.Weeklys - - 1998 - - 52 - -   -
      + Time + + Weekly + + Measures +
      + Year + + (All) + + Year + + Week + + Store Sales +
      + 1997 + + All Time.Weeklys + + 1997 + + 1 + + 11,734.43 +
      + 1997 + + All Time.Weeklys + + 1997 + + 2 + + 19,756.43 +
      + 1997 + + All Time.Weeklys + + 1997 + + 3 + + 19,933.22 +
      + 1997 + + All Time.Weeklys + + 1997 + + 4 + + 10,640.96 +
      + 1997 + + All Time.Weeklys + + 1997 + + 5 + + 12,339.06 +
      + 1997 + + All Time.Weeklys + + 1997 + + 6 + + 5,485.97 +
      + 1997 + + All Time.Weeklys + + 1997 + + 7 + + 11,368.84 +
      + 1997 + + All Time.Weeklys + + 1997 + + 8 + + 12,762.95 +
      + 1997 + + All Time.Weeklys + + 1997 + + 9 + + 11,095.62 +
      + 1997 + + All Time.Weeklys + + 1997 + + 10 + + 9,205.40 +
      + 1997 + + All Time.Weeklys + + 1997 + + 11 + + 7,775.74 +
      + 1997 + + All Time.Weeklys + + 1997 + + 12 + + 13,083.95 +
      + 1997 + + All Time.Weeklys + + 1997 + + 13 + + 18,164.50 +
      + 1997 + + All Time.Weeklys + + 1997 + + 14 + + 9,086.91 +
      + 1997 + + All Time.Weeklys + + 1997 + + 15 + + 9,534.01 +
      + 1997 + + All Time.Weeklys + + 1997 + + 16 + + 8,099.97 +
      + 1997 + + All Time.Weeklys + + 1997 + + 17 + + 14,361.15 +
      + 1997 + + All Time.Weeklys + + 1997 + + 18 + + 8,055.59 +
      + 1997 + + All Time.Weeklys + + 1997 + + 19 + + 10,046.38 +
      + 1997 + + All Time.Weeklys + + 1997 + + 20 + + 14,158.00 +
      + 1997 + + All Time.Weeklys + + 1997 + + 21 + + 9,629.54 +
      + 1997 + + All Time.Weeklys + + 1997 + + 22 + + 8,962.98 +
      + 1997 + + All Time.Weeklys + + 1997 + + 23 + + 5,178.50 +
      + 1997 + + All Time.Weeklys + + 1997 + + 24 + + 11,371.84 +
      + 1997 + + All Time.Weeklys + + 1997 + + 25 + + 6,601.20 +
      + 1997 + + All Time.Weeklys + + 1997 + + 26 + + 16,382.53 +
      + 1997 + + All Time.Weeklys + + 1997 + + 27 + + 9,821.26 +
      + 1997 + + All Time.Weeklys + + 1997 + + 28 + + 12,408.58 +
      + 1997 + + All Time.Weeklys + + 1997 + + 29 + + 11,010.72 +
      + 1997 + + All Time.Weeklys + + 1997 + + 30 + + 5,381.41 +
      + 1997 + + All Time.Weeklys + + 1997 + + 31 + + 10,383.56 +
      + 1997 + + All Time.Weeklys + + 1997 + + 32 + + 14,748.60 +
      + 1997 + + All Time.Weeklys + + 1997 + + 33 + + 10,048.16 +
      + 1997 + + All Time.Weeklys + + 1997 + + 34 + + 13,251.68 +
      + 1997 + + All Time.Weeklys + + 1997 + + 35 + + 9,789.56 +
      + 1997 + + All Time.Weeklys + + 1997 + + 36 + + 10,578.55 +
      + 1997 + + All Time.Weeklys + + 1997 + + 37 + + 8,956.30 +
      + 1997 + + All Time.Weeklys + + 1997 + + 38 + + 13,454.83 +
      + 1997 + + All Time.Weeklys + + 1997 + + 39 + + 11,885.60 +
      + 1997 + + All Time.Weeklys + + 1997 + + 40 + + 8,569.53 +
      + 1997 + + All Time.Weeklys + + 1997 + + 41 + + 4,560.28 +
      + 1997 + + All Time.Weeklys + + 1997 + + 42 + + 8,849.83 +
      + 1997 + + All Time.Weeklys + + 1997 + + 43 + + 14,110.56 +
      + 1997 + + All Time.Weeklys + + 1997 + + 44 + + 12,045.58 +
      + 1997 + + All Time.Weeklys + + 1997 + + 45 + + 4,707.93 +
      + 1997 + + All Time.Weeklys + + 1997 + + 46 + + 12,753.39 +
      + 1997 + + All Time.Weeklys + + 1997 + + 47 + + 12,406.81 +
      + 1997 + + All Time.Weeklys + + 1997 + + 48 + + 14,353.49 +
      + 1997 + + All Time.Weeklys + + 1997 + + 49 + + 11,425.66 +
      + 1997 + + All Time.Weeklys + + 1997 + + 50 + + 11,184.85 +
      + 1997 + + All Time.Weeklys + + 1997 + + 51 + + 11,880.04 +
      + 1997 + + All Time.Weeklys + + 1997 + + 52 + + 1,855.70 +
      + 1997 + + All Time.Weeklys + + 1998 + + 1 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 2 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 3 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 4 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 5 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 6 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 7 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 8 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 9 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 10 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 11 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 12 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 13 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 14 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 15 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 16 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 17 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 18 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 19 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 20 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 21 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 22 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 23 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 24 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 25 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 26 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 27 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 28 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 29 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 30 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 31 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 32 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 33 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 34 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 35 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 36 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 37 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 38 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 39 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 40 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 41 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 42 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 43 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 44 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 45 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 46 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 47 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 48 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 49 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 50 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 51 + +   +
      + 1997 + + All Time.Weeklys + + 1998 + + 52 + +   +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/skipping-level-false-false-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/skipping-level-false-false-false-result.html index 55282282..a2631e9c 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/skipping-level-false-false-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/skipping-level-false-false-false-result.html @@ -1,135 +1,135 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - All Products - - 266,773 - - 225,627.23 - - 565,238.13 -
      - Drink - - 24,597 - - 19,477.23 - - 48,836.21 -
      - Carbonated Beverages - - 3,407 - - 2,484.60 - - 6,236.35 -
      - Drinks - - 2,469 - - 2,247.11 - - 5,642.29 -
      - Hot Beverages - - 4,301 - - 3,708.08 - - 9,261.74 -
      - Pure Juice Beverages - - 3,396 - - 2,629.73 - - 6,608.15 -
      - Food - - 191,940 - - 163,270.72 - - 409,035.59 -
      - Non-Consumable - - 50,236 - - 42,879.28 - - 107,366.33 -
      +   + + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + All Products + + 266,773 + + 225,627.23 + + 565,238.13 +
      + Drink + + 24,597 + + 19,477.23 + + 48,836.21 +
      + Carbonated Beverages + + 3,407 + + 2,484.60 + + 6,236.35 +
      + Drinks + + 2,469 + + 2,247.11 + + 5,642.29 +
      + Hot Beverages + + 4,301 + + 3,708.08 + + 9,261.74 +
      + Pure Juice Beverages + + 3,396 + + 2,629.73 + + 6,608.15 +
      + Food + + 191,940 + + 163,270.72 + + 409,035.59 +
      + Non-Consumable + + 50,236 + + 42,879.28 + + 107,366.33 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/skipping-level-false-false-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/skipping-level-false-false-true-result.html index 9e3b18aa..da6012ae 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/skipping-level-false-false-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/skipping-level-false-false-true-result.html @@ -1,144 +1,144 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - All Products - - 266,773 - - 225,627.23 - - 565,238.13 -
      - All Products - - Drink - - 24,597 - - 19,477.23 - - 48,836.21 -
      - Drink - - Beverages - - Carbonated Beverages - - 3,407 - - 2,484.60 - - 6,236.35 -
      - Drinks - - 2,469 - - 2,247.11 - - 5,642.29 -
      - Hot Beverages - - 4,301 - - 3,708.08 - - 9,261.74 -
      - Pure Juice Beverages - - 3,396 - - 2,629.73 - - 6,608.15 -
      - Food - - 191,940 - - 163,270.72 - - 409,035.59 -
      - Non-Consumable - - 50,236 - - 42,879.28 - - 107,366.33 -
      +   + + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + All Products + + 266,773 + + 225,627.23 + + 565,238.13 +
      + All Products + + Drink + + 24,597 + + 19,477.23 + + 48,836.21 +
      + Drink + + Beverages + + Carbonated Beverages + + 3,407 + + 2,484.60 + + 6,236.35 +
      + Drinks + + 2,469 + + 2,247.11 + + 5,642.29 +
      + Hot Beverages + + 4,301 + + 3,708.08 + + 9,261.74 +
      + Pure Juice Beverages + + 3,396 + + 2,629.73 + + 6,608.15 +
      + Food + + 191,940 + + 163,270.72 + + 409,035.59 +
      + Non-Consumable + + 50,236 + + 42,879.28 + + 107,366.33 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/skipping-level-false-true-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/skipping-level-false-true-false-result.html index 48da55c8..8825dba0 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/skipping-level-false-true-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/skipping-level-false-true-false-result.html @@ -1,146 +1,146 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Measures -
      - Promotion Media - - Product - - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - All Products - - 266,773 - - 225,627.23 - - 565,238.13 -
      - Drink - - 24,597 - - 19,477.23 - - 48,836.21 -
      - Carbonated Beverages - - 3,407 - - 2,484.60 - - 6,236.35 -
      - Drinks - - 2,469 - - 2,247.11 - - 5,642.29 -
      - Hot Beverages - - 4,301 - - 3,708.08 - - 9,261.74 -
      - Pure Juice Beverages - - 3,396 - - 2,629.73 - - 6,608.15 -
      - Food - - 191,940 - - 163,270.72 - - 409,035.59 -
      - Non-Consumable - - 50,236 - - 42,879.28 - - 107,366.33 -
      +   + + Measures +
      + Promotion Media + + Product + + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + All Products + + 266,773 + + 225,627.23 + + 565,238.13 +
      + Drink + + 24,597 + + 19,477.23 + + 48,836.21 +
      + Carbonated Beverages + + 3,407 + + 2,484.60 + + 6,236.35 +
      + Drinks + + 2,469 + + 2,247.11 + + 5,642.29 +
      + Hot Beverages + + 4,301 + + 3,708.08 + + 9,261.74 +
      + Pure Juice Beverages + + 3,396 + + 2,629.73 + + 6,608.15 +
      + Food + + 191,940 + + 163,270.72 + + 409,035.59 +
      + Non-Consumable + + 50,236 + + 42,879.28 + + 107,366.33 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/skipping-level-false-true-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/skipping-level-false-true-true-result.html index 83596927..575c449f 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/skipping-level-false-true-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/skipping-level-false-true-true-result.html @@ -1,167 +1,167 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      - Promotion Media - - Product - - Measures -
      - (All) - - (All) - - Product Family - - Product Department - - Product Category - - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - All Products - - 266,773 - - 225,627.23 - - 565,238.13 -
      - All Products - - Drink - - 24,597 - - 19,477.23 - - 48,836.21 -
      - Drink - - Beverages - - Carbonated Beverages - - 3,407 - - 2,484.60 - - 6,236.35 -
      - Drinks - - 2,469 - - 2,247.11 - - 5,642.29 -
      - Hot Beverages - - 4,301 - - 3,708.08 - - 9,261.74 -
      - Pure Juice Beverages - - 3,396 - - 2,629.73 - - 6,608.15 -
      - Food - - 191,940 - - 163,270.72 - - 409,035.59 -
      - Non-Consumable - - 50,236 - - 42,879.28 - - 107,366.33 -
      + Promotion Media + + Product + + Measures +
      + (All) + + (All) + + Product Family + + Product Department + + Product Category + + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + All Products + + 266,773 + + 225,627.23 + + 565,238.13 +
      + All Products + + Drink + + 24,597 + + 19,477.23 + + 48,836.21 +
      + Drink + + Beverages + + Carbonated Beverages + + 3,407 + + 2,484.60 + + 6,236.35 +
      + Drinks + + 2,469 + + 2,247.11 + + 5,642.29 +
      + Hot Beverages + + 4,301 + + 3,708.08 + + 9,261.74 +
      + Pure Juice Beverages + + 3,396 + + 2,629.73 + + 6,608.15 +
      + Food + + 191,940 + + 163,270.72 + + 409,035.59 +
      + Non-Consumable + + 50,236 + + 42,879.28 + + 107,366.33 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/skipping-level-true-false-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/skipping-level-true-false-false-result.html index 2c1b34d5..4b4fa417 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/skipping-level-true-false-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/skipping-level-true-false-false-result.html @@ -1,156 +1,156 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - All Products - - 266,773 - - 225,627.23 - - 565,238.13 -
      - All Media - - Drink - - 24,597 - - 19,477.23 - - 48,836.21 -
      - All Media - - Carbonated Beverages - - 3,407 - - 2,484.60 - - 6,236.35 -
      - All Media - - Drinks - - 2,469 - - 2,247.11 - - 5,642.29 -
      - All Media - - Hot Beverages - - 4,301 - - 3,708.08 - - 9,261.74 -
      - All Media - - Pure Juice Beverages - - 3,396 - - 2,629.73 - - 6,608.15 -
      - All Media - - Food - - 191,940 - - 163,270.72 - - 409,035.59 -
      - All Media - - Non-Consumable - - 50,236 - - 42,879.28 - - 107,366.33 -
      +   + + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + All Products + + 266,773 + + 225,627.23 + + 565,238.13 +
      + All Media + + Drink + + 24,597 + + 19,477.23 + + 48,836.21 +
      + All Media + + Carbonated Beverages + + 3,407 + + 2,484.60 + + 6,236.35 +
      + All Media + + Drinks + + 2,469 + + 2,247.11 + + 5,642.29 +
      + All Media + + Hot Beverages + + 4,301 + + 3,708.08 + + 9,261.74 +
      + All Media + + Pure Juice Beverages + + 3,396 + + 2,629.73 + + 6,608.15 +
      + All Media + + Food + + 191,940 + + 163,270.72 + + 409,035.59 +
      + All Media + + Non-Consumable + + 50,236 + + 42,879.28 + + 107,366.33 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/skipping-level-true-false-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/skipping-level-true-false-true-result.html index 4589d0f9..50c55867 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/skipping-level-true-false-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/skipping-level-true-false-true-result.html @@ -1,201 +1,201 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - All Products - - 266,773 - - 225,627.23 - - 565,238.13 -
      - All Media - - All Products - - Drink - - 24,597 - - 19,477.23 - - 48,836.21 -
      - All Media - - All Products - - Drink - - Beverages - - Carbonated Beverages - - 3,407 - - 2,484.60 - - 6,236.35 -
      - All Media - - All Products - - Drink - - Beverages - - Drinks - - 2,469 - - 2,247.11 - - 5,642.29 -
      - All Media - - All Products - - Drink - - Beverages - - Hot Beverages - - 4,301 - - 3,708.08 - - 9,261.74 -
      - All Media - - All Products - - Drink - - Beverages - - Pure Juice Beverages - - 3,396 - - 2,629.73 - - 6,608.15 -
      - All Media - - All Products - - Food - - 191,940 - - 163,270.72 - - 409,035.59 -
      - All Media - - All Products - - Non-Consumable - - 50,236 - - 42,879.28 - - 107,366.33 -
      +   + + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + All Products + + 266,773 + + 225,627.23 + + 565,238.13 +
      + All Media + + All Products + + Drink + + 24,597 + + 19,477.23 + + 48,836.21 +
      + All Media + + All Products + + Drink + + Beverages + + Carbonated Beverages + + 3,407 + + 2,484.60 + + 6,236.35 +
      + All Media + + All Products + + Drink + + Beverages + + Drinks + + 2,469 + + 2,247.11 + + 5,642.29 +
      + All Media + + All Products + + Drink + + Beverages + + Hot Beverages + + 4,301 + + 3,708.08 + + 9,261.74 +
      + All Media + + All Products + + Drink + + Beverages + + Pure Juice Beverages + + 3,396 + + 2,629.73 + + 6,608.15 +
      + All Media + + All Products + + Food + + 191,940 + + 163,270.72 + + 409,035.59 +
      + All Media + + All Products + + Non-Consumable + + 50,236 + + 42,879.28 + + 107,366.33 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/skipping-level-true-true-false-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/skipping-level-true-true-false-result.html index 1e6f6d54..1c7919e3 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/skipping-level-true-true-false-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/skipping-level-true-true-false-result.html @@ -1,173 +1,173 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      -   - - Measures - - Measures - - Measures -
      - Promotion Media - - Product - - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - All Products - - 266,773 - - 225,627.23 - - 565,238.13 -
      - All Media - - Drink - - 24,597 - - 19,477.23 - - 48,836.21 -
      - All Media - - Carbonated Beverages - - 3,407 - - 2,484.60 - - 6,236.35 -
      - All Media - - Drinks - - 2,469 - - 2,247.11 - - 5,642.29 -
      - All Media - - Hot Beverages - - 4,301 - - 3,708.08 - - 9,261.74 -
      - All Media - - Pure Juice Beverages - - 3,396 - - 2,629.73 - - 6,608.15 -
      - All Media - - Food - - 191,940 - - 163,270.72 - - 409,035.59 -
      - All Media - - Non-Consumable - - 50,236 - - 42,879.28 - - 107,366.33 -
      +   + + Measures + + Measures + + Measures +
      + Promotion Media + + Product + + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + All Products + + 266,773 + + 225,627.23 + + 565,238.13 +
      + All Media + + Drink + + 24,597 + + 19,477.23 + + 48,836.21 +
      + All Media + + Carbonated Beverages + + 3,407 + + 2,484.60 + + 6,236.35 +
      + All Media + + Drinks + + 2,469 + + 2,247.11 + + 5,642.29 +
      + All Media + + Hot Beverages + + 4,301 + + 3,708.08 + + 9,261.74 +
      + All Media + + Pure Juice Beverages + + 3,396 + + 2,629.73 + + 6,608.15 +
      + All Media + + Food + + 191,940 + + 163,270.72 + + 409,035.59 +
      + All Media + + Non-Consumable + + 50,236 + + 42,879.28 + + 107,366.33 +
      diff --git a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/skipping-level-true-true-true-result.html b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/skipping-level-true-true-true-result.html index be56a057..451a8538 100644 --- a/pivot4j-core/src/test/resources/org/pivot4j/ui/html/skipping-level-true-true-true-result.html +++ b/pivot4j-core/src/test/resources/org/pivot4j/ui/html/skipping-level-true-true-true-result.html @@ -1,230 +1,230 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      - Promotion Media - - Product - - Measures - - Measures - - Measures -
      - (All) - - (All) - - Product Family - - Product Department - - Product Category - - Unit Sales - - Store Cost - - Store Sales -
      - All Media - - All Products - - 266,773 - - 225,627.23 - - 565,238.13 -
      - All Media - - All Products - - Drink - - 24,597 - - 19,477.23 - - 48,836.21 -
      - All Media - - All Products - - Drink - - Beverages - - Carbonated Beverages - - 3,407 - - 2,484.60 - - 6,236.35 -
      - All Media - - All Products - - Drink - - Beverages - - Drinks - - 2,469 - - 2,247.11 - - 5,642.29 -
      - All Media - - All Products - - Drink - - Beverages - - Hot Beverages - - 4,301 - - 3,708.08 - - 9,261.74 -
      - All Media - - All Products - - Drink - - Beverages - - Pure Juice Beverages - - 3,396 - - 2,629.73 - - 6,608.15 -
      - All Media - - All Products - - Food - - 191,940 - - 163,270.72 - - 409,035.59 -
      - All Media - - All Products - - Non-Consumable - - 50,236 - - 42,879.28 - - 107,366.33 -
      + Promotion Media + + Product + + Measures + + Measures + + Measures +
      + (All) + + (All) + + Product Family + + Product Department + + Product Category + + Unit Sales + + Store Cost + + Store Sales +
      + All Media + + All Products + + 266,773 + + 225,627.23 + + 565,238.13 +
      + All Media + + All Products + + Drink + + 24,597 + + 19,477.23 + + 48,836.21 +
      + All Media + + All Products + + Drink + + Beverages + + Carbonated Beverages + + 3,407 + + 2,484.60 + + 6,236.35 +
      + All Media + + All Products + + Drink + + Beverages + + Drinks + + 2,469 + + 2,247.11 + + 5,642.29 +
      + All Media + + All Products + + Drink + + Beverages + + Hot Beverages + + 4,301 + + 3,708.08 + + 9,261.74 +
      + All Media + + All Products + + Drink + + Beverages + + Pure Juice Beverages + + 3,396 + + 2,629.73 + + 6,608.15 +
      + All Media + + All Products + + Food + + 191,940 + + 163,270.72 + + 409,035.59 +
      + All Media + + All Products + + Non-Consumable + + 50,236 + + 42,879.28 + + 107,366.33 +
      diff --git a/pivot4j-pentaho/.classpath b/pivot4j-pentaho/.classpath index 658fc2e3..021384b3 100644 --- a/pivot4j-pentaho/.classpath +++ b/pivot4j-pentaho/.classpath @@ -1,31 +1,31 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pivot4j-pentaho/.project b/pivot4j-pentaho/.project index fd4bced4..281abb69 100644 --- a/pivot4j-pentaho/.project +++ b/pivot4j-pentaho/.project @@ -1,24 +1,24 @@ - pivot4j-pentaho - - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.m2e.core.maven2Builder - - - - - - org.sonar.ide.eclipse.core.sonarNature - org.eclipse.jdt.core.javanature - org.eclipse.m2e.core.maven2Nature - + pivot4j-pentaho + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.sonar.ide.eclipse.core.sonarNature + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + diff --git a/pivot4j-pentaho/pom.xml b/pivot4j-pentaho/pom.xml index 7f2d87c9..f7b87af4 100644 --- a/pivot4j-pentaho/pom.xml +++ b/pivot4j-pentaho/pom.xml @@ -1,366 +1,366 @@ - 4.0.0 - - org.pivot4j - pivot4j - 1.0-SNAPSHOT - ../pom.xml - + 4.0.0 + + org.pivot4j + pivot4j + 1.0-SNAPSHOT + ../pom.xml + - pivot4j-pentaho - Pivot4J Pentaho - Pivot4J Pentatho is an OLAP analysis plugin for BI platform based on Pivot4J library. - jar + pivot4j-pentaho + Pivot4J Pentaho + Pivot4J Pentatho is an OLAP analysis plugin for BI platform based on Pivot4J library. + jar - - Development - ${maven.build.timestamp} - yyyyMMddHHmm - + + Development + ${maven.build.timestamp} + yyyyMMddHHmm + - - - - org.apache.maven.plugins - maven-jar-plugin - - ${project.build.directory}/plugin/lib - - - true - true - - - - - - org.apache.portals.jetspeed-2 - jetspeed-unpack-maven-plugin - ${version.plugin.jetspeed} - - - validate - - unpack - - - - org.pivot4j:pivot4j-analytics:war - true - ${project.build.directory}/plugin - - - - webapp - *.xhtml - - - WEB-INF - webapp/WEB-INF - *.xml - - - WEB-INF/lib - lib - *.jar - olap4j*,xercesImpl*,xml-apis*,xalan*,xmlParser*,xmlbeans*,eigenbase*,derby*,mondrian*,commons-logging*,log4j*,slf4j*,poi*,serializer* - - - resources - webapp/resources - **/* - - - - - - - - - org.pivot4j - pivot4j-analytics - ${project.version} - war - - - - - org.apache.maven.plugins - maven-dependency-plugin - ${version.plugin.dependency} - - - copy-artifacts - package - - copy - - - - - org.pivot4j - pivot4j-analytics - ${project.version} - classes - true - pivot4j-analytics-${project.version}.jar - - - ${project.build.directory}/plugin/lib - - - - copy-dependencies - package - - copy-dependencies - - - ${project.build.directory}/plugin/lib - true - backport-util-concurrent - - - - - - org.codehaus.mojo - xml-maven-plugin - ${version.plugin.xml} - - - prepare-package - - transform - - - - - - - ${project.build.directory}/plugin/webapp/WEB-INF - - web.xml - - ${basedir}/src/main/xsl/web.xsl - - - ${project.build.directory}/plugin/webapp/WEB-INF - - faces-config.xml - - ${basedir}/src/main/xsl/faces-config.xsl - - - - - - maven-resources-plugin - ${version.plugin.resources} - - - copy-resources - validate - - copy-resources - - - ${project.build.directory}/plugin - true - - - ${basedir}/src/main/plugin - - *.xml - - - - ${basedir}/src/main - - webapp/** - - - - - - - - - org.apache.maven.plugins - maven-assembly-plugin - ${version.plugin.assembly} - - ${basedir}/src/main/assembly/plugin.xml - ${project.artifactId}-${project.version} - - - - make-assembly - package - - single - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - ${version.plugin.javadoc} - - - javadoc-jar - package - - jar - - - - - - org.apache.maven.plugins - maven-source-plugin - ${version.plugin.source} - - - attach-sources - verify - - jar-no-fork - - - - - - + + + + org.apache.maven.plugins + maven-jar-plugin + + ${project.build.directory}/plugin/lib + + + true + true + + + + + + org.apache.portals.jetspeed-2 + jetspeed-unpack-maven-plugin + ${version.plugin.jetspeed} + + + validate + + unpack + + + + org.pivot4j:pivot4j-analytics:war + true + ${project.build.directory}/plugin + + + + webapp + *.xhtml + + + WEB-INF + webapp/WEB-INF + *.xml + + + WEB-INF/lib + lib + *.jar + olap4j*,xercesImpl*,xml-apis*,xalan*,xmlParser*,xmlbeans*,eigenbase*,derby*,mondrian*,commons-logging*,log4j*,slf4j*,poi*,serializer* + + + resources + webapp/resources + **/* + + + + + + + + + org.pivot4j + pivot4j-analytics + ${project.version} + war + + + + + org.apache.maven.plugins + maven-dependency-plugin + ${version.plugin.dependency} + + + copy-artifacts + package + + copy + + + + + org.pivot4j + pivot4j-analytics + ${project.version} + classes + true + pivot4j-analytics-${project.version}.jar + + + ${project.build.directory}/plugin/lib + + + + copy-dependencies + package + + copy-dependencies + + + ${project.build.directory}/plugin/lib + true + backport-util-concurrent + + + + + + org.codehaus.mojo + xml-maven-plugin + ${version.plugin.xml} + + + prepare-package + + transform + + + + + + + ${project.build.directory}/plugin/webapp/WEB-INF + + web.xml + + ${basedir}/src/main/xsl/web.xsl + + + ${project.build.directory}/plugin/webapp/WEB-INF + + faces-config.xml + + ${basedir}/src/main/xsl/faces-config.xsl + + + + + + maven-resources-plugin + ${version.plugin.resources} + + + copy-resources + validate + + copy-resources + + + ${project.build.directory}/plugin + true + + + ${basedir}/src/main/plugin + + *.xml + + + + ${basedir}/src/main + + webapp/** + + + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + ${version.plugin.assembly} + + ${basedir}/src/main/assembly/plugin.xml + ${project.artifactId}-${project.version} + + + + make-assembly + package + + single + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${version.plugin.javadoc} + + + javadoc-jar + package + + jar + + + + + + org.apache.maven.plugins + maven-source-plugin + ${version.plugin.source} + + + attach-sources + verify + + jar-no-fork + + + + + + - - - org.pivot4j - pivot4j-analytics - ${project.version} - classes - - - org.glassfish - javax.faces - - - - - org.apache.myfaces.core - myfaces-api - ${version.myfaces} - - - org.apache.myfaces.core - myfaces-impl - ${version.myfaces} - - - pentaho - pentaho-platform-core - ${version.pentaho} - provided - - - gnujaxp - gnujaxp - - - xerces - xmlParserAPIs - - - - - pentaho - pentaho-platform-api - ${version.pentaho} - provided - - - pentaho - pentaho-platform-extensions - ${version.pentaho} - provided - - - javax.faces - jsf-api - - - org.apache.xbean - xbean - - - adaptx - adaptx - - - org.jvnet.staxex - stax-ex - - - net.sourceforge.nekohtml - nekohtml - - - janino - janino - - - xml-apis - xmlParserAPIs - - - xerces - xmlParserAPIs - - - - - pentaho - pentaho-connections - ${version.pentaho} - provided - - - eigenbase - eigenbase-xom - ${version.eigenbase.xom} - provided - - - javax.servlet - servlet-api - ${version.servlet} - provided - - - javax.el - javax.el-api - ${version.el} - provided - - - backport-util-concurrent - backport-util-concurrent - ${version.backport.concurrent} - - + + + org.pivot4j + pivot4j-analytics + ${project.version} + classes + + + org.glassfish + javax.faces + + + + + org.apache.myfaces.core + myfaces-api + ${version.myfaces} + + + org.apache.myfaces.core + myfaces-impl + ${version.myfaces} + + + pentaho + pentaho-platform-core + ${version.pentaho} + provided + + + gnujaxp + gnujaxp + + + xerces + xmlParserAPIs + + + + + pentaho + pentaho-platform-api + ${version.pentaho} + provided + + + pentaho + pentaho-platform-extensions + ${version.pentaho} + provided + + + javax.faces + jsf-api + + + org.apache.xbean + xbean + + + adaptx + adaptx + + + org.jvnet.staxex + stax-ex + + + net.sourceforge.nekohtml + nekohtml + + + janino + janino + + + xml-apis + xmlParserAPIs + + + xerces + xmlParserAPIs + + + + + pentaho + pentaho-connections + ${version.pentaho} + provided + + + eigenbase + eigenbase-xom + ${version.eigenbase.xom} + provided + + + javax.servlet + servlet-api + ${version.servlet} + provided + + + javax.el + javax.el-api + ${version.el} + provided + + + backport-util-concurrent + backport-util-concurrent + ${version.backport.concurrent} + + - - - pentaho-third-party - Pentaho Third Party Repository - http://repo.pentaho.org/artifactory/third-party/ - - - prime-repo - PrimeFaces Maven Repository - http://repository.primefaces.org - default - - + + + pentaho-third-party + Pentaho Third Party Repository + http://repo.pentaho.org/artifactory/third-party/ + + + prime-repo + PrimeFaces Maven Repository + http://repository.primefaces.org + default + + diff --git a/pivot4j-pentaho/src/main/assembly/plugin.xml b/pivot4j-pentaho/src/main/assembly/plugin.xml index ef5128ab..8f72db4c 100644 --- a/pivot4j-pentaho/src/main/assembly/plugin.xml +++ b/pivot4j-pentaho/src/main/assembly/plugin.xml @@ -1,42 +1,42 @@ - plugin - - tar.gz - zip - - false - - - ${project.build.directory}/plugin - /pivot4j - - **/* - - - *.xml - **/web.xml - **/faces-config.xml - - false - - - ${project.build.directory}/generated-resources/xml/xslt - /pivot4j/webapp/WEB-INF - - **/web.xml - **/faces-config.xml - - false - - - ${project.build.directory}/plugin - /pivot4j - - *.xml - - true - - + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd"> + plugin + + tar.gz + zip + + false + + + ${project.build.directory}/plugin + /pivot4j + + **/* + + + *.xml + **/web.xml + **/faces-config.xml + + false + + + ${project.build.directory}/generated-resources/xml/xslt + /pivot4j/webapp/WEB-INF + + **/web.xml + **/faces-config.xml + + false + + + ${project.build.directory}/plugin + /pivot4j + + *.xml + + true + + diff --git a/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/content/ReportContentEditor.java b/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/content/ReportContentEditor.java index 7eaa1440..d27a36a8 100644 --- a/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/content/ReportContentEditor.java +++ b/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/content/ReportContentEditor.java @@ -2,13 +2,13 @@ public class ReportContentEditor extends ReportContentGenerator { - private static final long serialVersionUID = 2954902953680461053L; + private static final long serialVersionUID = 2954902953680461053L; - /** - * @see org.pivot4j.pentaho.content.ReportContentGenerator#isEditable() - */ - @Override - public boolean isEditable() { - return true; - } + /** + * @see org.pivot4j.pentaho.content.ReportContentGenerator#isEditable() + */ + @Override + public boolean isEditable() { + return true; + } } diff --git a/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/content/ReportContentGenerator.java b/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/content/ReportContentGenerator.java index 5b6c42aa..65729c6c 100644 --- a/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/content/ReportContentGenerator.java +++ b/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/content/ReportContentGenerator.java @@ -13,48 +13,50 @@ public class ReportContentGenerator extends BaseContentGenerator { - private static final long serialVersionUID = 7257498161100674425L; - - private transient Log log; - - /** - * @see org.pentaho.platform.engine.services.solution.BaseContentGenerator#getLogger() - */ - @Override - public Log getLogger() { - if (log == null) { - this.log = LogFactory.getLog(getClass()); - } - - return log; - } - - /** - * @return the editable - */ - public boolean isEditable() { - return false; - } - - /** - * @throws IOException - * @throws ServletException - * @see org.pentaho.platform.engine.services.solution.BaseContentGenerator#createContent() - */ - @Override - public void createContent() throws ServletException, IOException { - HttpServletRequest request = (HttpServletRequest) this.parameterProviders - .get("path").getParameter("httprequest"); - - HttpServletResponse response = (HttpServletResponse) this.parameterProviders - .get("path").getParameter("httpresponse"); - - RepositoryFile file = (RepositoryFile) parameterProviders.get("path") - .getParameter("file"); - - request.setAttribute("file", file); - request.getRequestDispatcher( - "/plugin/pivot4j/faces/open.xhtml?editable=" + isEditable()) - .forward(request, response); - } + private static final long serialVersionUID = 7257498161100674425L; + + private transient Log log; + + /** + * @see + * org.pentaho.platform.engine.services.solution.BaseContentGenerator#getLogger() + */ + @Override + public Log getLogger() { + if (log == null) { + this.log = LogFactory.getLog(getClass()); + } + + return log; + } + + /** + * @return the editable + */ + public boolean isEditable() { + return false; + } + + /** + * @throws IOException + * @throws ServletException + * @see + * org.pentaho.platform.engine.services.solution.BaseContentGenerator#createContent() + */ + @Override + public void createContent() throws ServletException, IOException { + HttpServletRequest request = (HttpServletRequest) this.parameterProviders + .get("path").getParameter("httprequest"); + + HttpServletResponse response = (HttpServletResponse) this.parameterProviders + .get("path").getParameter("httpresponse"); + + RepositoryFile file = (RepositoryFile) parameterProviders.get("path") + .getParameter("file"); + + request.setAttribute("file", file); + request.getRequestDispatcher( + "/plugin/pivot4j/faces/open.xhtml?editable=" + isEditable()) + .forward(request, response); + } } diff --git a/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/datasource/MdxOlap4JDataSource.java b/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/datasource/MdxOlap4JDataSource.java index 2a21f16d..09c8c8de 100644 --- a/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/datasource/MdxOlap4JDataSource.java +++ b/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/datasource/MdxOlap4JDataSource.java @@ -15,72 +15,72 @@ public class MdxOlap4JDataSource extends AbstractOlapDataSource { - private IPentahoSession session; - - private Properties properties; - - private List roleNames; - - /** - * @param session - * @param properties - * @param roleNames - */ - public MdxOlap4JDataSource(IPentahoSession session, Properties properties, - List roleNames) { - if (session == null) { - throw new IllegalAccessError("Required argument 'session' is null."); - } - - if (properties == null) { - throw new IllegalAccessError( - "Required argument 'properties' is null."); - } - - this.session = session; - this.properties = properties; - this.roleNames = roleNames; - } - - /** - * @return the session - */ - public IPentahoSession getSession() { - return session; - } - - /** - * @return the properties - */ - public Properties getProperties() { - return properties; - } - - /** - * @return the roleNames - */ - public List getRoles() { - return roleNames; - } - - /** - * @see org.pivot4j.datasource.AbstractOlapDataSource#createConnection(java - * .lang.String, java.lang.String) - */ - @Override - protected OlapConnection createConnection(String userName, String password) - throws SQLException { - MDXOlap4jConnection connection = (MDXOlap4jConnection) PentahoConnectionFactory - .getConnection(IPentahoConnection.MDX_OLAP4J_DATASOURCE, - properties, session, null); - - OlapConnection olap4JCon = connection.getConnection(); - - if (roleNames != null && !roleNames.isEmpty()) { - MondrianOlap4jConnection monCon = (MondrianOlap4jConnection) olap4JCon; - monCon.setRoleNames(roleNames); - } - - return olap4JCon; - } + private IPentahoSession session; + + private Properties properties; + + private List roleNames; + + /** + * @param session + * @param properties + * @param roleNames + */ + public MdxOlap4JDataSource(IPentahoSession session, Properties properties, + List roleNames) { + if (session == null) { + throw new IllegalAccessError("Required argument 'session' is null."); + } + + if (properties == null) { + throw new IllegalAccessError( + "Required argument 'properties' is null."); + } + + this.session = session; + this.properties = properties; + this.roleNames = roleNames; + } + + /** + * @return the session + */ + public IPentahoSession getSession() { + return session; + } + + /** + * @return the properties + */ + public Properties getProperties() { + return properties; + } + + /** + * @return the roleNames + */ + public List getRoles() { + return roleNames; + } + + /** + * @see org.pivot4j.datasource.AbstractOlapDataSource#createConnection(java + * .lang.String, java.lang.String) + */ + @Override + protected OlapConnection createConnection(String userName, String password) + throws SQLException { + MDXOlap4jConnection connection = (MDXOlap4jConnection) PentahoConnectionFactory + .getConnection(IPentahoConnection.MDX_OLAP4J_DATASOURCE, + properties, session, null); + + OlapConnection olap4JCon = connection.getConnection(); + + if (roleNames != null && !roleNames.isEmpty()) { + MondrianOlap4jConnection monCon = (MondrianOlap4jConnection) olap4JCon; + monCon.setRoleNames(roleNames); + } + + return olap4JCon; + } } diff --git a/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/datasource/PentahoDataSourceDefinition.java b/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/datasource/PentahoDataSourceDefinition.java index 3ae5ccdc..a10c036a 100644 --- a/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/datasource/PentahoDataSourceDefinition.java +++ b/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/datasource/PentahoDataSourceDefinition.java @@ -5,24 +5,24 @@ public class PentahoDataSourceDefinition extends AbstractDataSourceInfo { - private static final long serialVersionUID = 85152867828084878L; + private static final long serialVersionUID = 85152867828084878L; - /** - * @param catalog - */ - public PentahoDataSourceDefinition(MondrianCatalog catalog) { - if (catalog != null) { - setName(catalog.getName()); - setDescription(catalog.getDefinition()); - } - } + /** + * @param catalog + */ + public PentahoDataSourceDefinition(MondrianCatalog catalog) { + if (catalog != null) { + setName(catalog.getName()); + setDescription(catalog.getDefinition()); + } + } - /** - * @param catalogName - * @param description - */ - public PentahoDataSourceDefinition(String catalogName, String description) { - setName(catalogName); - setDescription(description); - } + /** + * @param catalogName + * @param description + */ + public PentahoDataSourceDefinition(String catalogName, String description) { + setName(catalogName); + setDescription(description); + } } diff --git a/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/datasource/PentahoDataSourceManager.java b/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/datasource/PentahoDataSourceManager.java index b28be065..5123c9da 100644 --- a/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/datasource/PentahoDataSourceManager.java +++ b/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/datasource/PentahoDataSourceManager.java @@ -37,258 +37,264 @@ import org.slf4j.Logger; public class PentahoDataSourceManager extends - AbstractDataSourceManager { - - private IPentahoSession session; - - private IMondrianCatalogService catalogService; - - private IConnectionUserRoleMapper roleMapper; - - /** - * @see org.pivot4j.analytics.datasource.AbstractDataSourceManager#initialize() - */ - @Override - protected void initialize() { - this.session = PentahoSessionHolder.getSession(); - this.catalogService = PentahoSystem.get(IMondrianCatalogService.class, - session); - - if (PentahoSystem.getObjectFactory().objectDefined( - MDX_CONNECTION_MAPPER_KEY)) { - this.roleMapper = PentahoSystem.get( - IConnectionUserRoleMapper.class, MDX_CONNECTION_MAPPER_KEY, - null); - } - - super.initialize(); - } - - /** - * @see org.pivot4j.analytics.datasource.AbstractDataSourceManager#destroy() - */ - @Override - protected void destroy() { - this.session = null; - this.catalogService = null; - } - - /** - * @return the session - */ - protected IPentahoSession getSession() { - return session; - } - - /** - * @return the catalogService - */ - protected IMondrianCatalogService getCatalogService() { - return catalogService; - } - - /** - * @return the roleMapper - */ - protected IConnectionUserRoleMapper getRoleMapper() { - return roleMapper; - } - - /** - * @see org.pivot4j.analytics.datasource.DataSourceManager#getCatalogs() - */ - @Override - public List getCatalogs() { - List catalogs = catalogService.listCatalogs(session, - false); - - List result = new LinkedList(); - - for (MondrianCatalog catalog : catalogs) { - if (!getCubes(catalog.getName()).isEmpty()) { - result.add(new CatalogInfo(catalog.getName(), - catalog.getName(), catalog.getDefinition())); - } - } - - return result; - } - - /** - * @param name - * @return - */ - public MondrianCatalog getCatalog(String name) { - return catalogService.getCatalog(name, session); - } - - /** - * @see org.pivot4j.analytics.datasource.DataSourceManager#getCubes(java.lang.String) - */ - @Override - public List getCubes(String catalogName) { - if (catalogName == null) { - throw new NullArgumentException("catalogName"); - } - - List cubes = new LinkedList(); - - MondrianCatalog catalog = getCatalog(catalogName); - - if (catalog == null) { - throw new IllegalArgumentException( - "The catalog with the given name does not exist : " - + catalogName); - } - - OlapDataSource dataSource = createDataSource(new PentahoDataSourceDefinition( - catalog)); - OlapConnection con = null; - - try { - con = dataSource.getConnection(); - - List olapCubes = con.getOlapSchema().getCubes(); - - for (Cube cube : olapCubes) { - if (cube.isVisible()) { - cubes.add(new CubeInfo(cube.getName(), cube.getCaption(), - cube.getDescription())); - } - } - } catch (SQLException e) { - throw new UnhandledException(e); - } finally { - DbUtils.closeQuietly(con); - } - - return cubes; - } - - /** - * @see org.pivot4j.analytics.datasource.AbstractDataSourceManager#registerDefinitions() - */ - @Override - protected void registerDefinitions() { - List catalogs = catalogService.listCatalogs(session, - false); - - for (MondrianCatalog catalog : catalogs) { - registerDefinition(new PentahoDataSourceDefinition(catalog)); - } - } - - /** - * @see org.pivot4j.analytics.datasource.AbstractDataSourceManager#getDefinition(org.pivot4j.analytics.datasource.ConnectionInfo) - */ - @Override - protected synchronized PentahoDataSourceDefinition getDefinition( - ConnectionInfo connectionInfo) { - PentahoDataSourceDefinition definition = super - .getDefinition(connectionInfo); - - if (definition == null) { - MondrianCatalog catalog = catalogService.getCatalog( - connectionInfo.getCatalogName(), session); - - if (catalog != null) { - definition = new PentahoDataSourceDefinition(catalog); - registerDefinition(definition); - } - } - - return definition; - } - - /** - * @see org.pivot4j.analytics.datasource.AbstractDataSourceManager#createDataSourceDefinition(org.apache.commons.configuration.HierarchicalConfiguration) - */ - @Override - protected PentahoDataSourceDefinition createDataSourceDefinition( - HierarchicalConfiguration configuration) { - return null; - } - - /** - * @see org.pivot4j.analytics.datasource.AbstractDataSourceManager#createDataSource(org.pivot4j.analytics.datasource.DataSourceInfo) - */ - @Override - protected OlapDataSource createDataSource( - PentahoDataSourceDefinition definition) { - if (definition == null) { - return null; - } - - MondrianCatalog catalog = getCatalog(definition.getName()); - - if (catalog == null) { - Logger logger = getLogger(); - if (logger.isWarnEnabled()) { - logger.warn("Unable to find catalog with name : " - + definition.getName()); - } - - return null; - } - - Util.PropertyList parsedProperties = Util.parseConnectString(catalog - .getDataSourceInfo()); - - StringBuilder builder = new StringBuilder(); - builder.append("jdbc:mondrian:"); - builder.append("Catalog="); - builder.append(catalog.getDefinition()); - builder.append("; "); - - Iterator> it = parsedProperties.iterator(); - - while (it.hasNext()) { - Pair pair = it.next(); - builder.append(pair.getKey()); - builder.append("="); - builder.append(pair.getValue()); - builder.append("; "); - } - - builder.append("PoolNeeded=false; "); - builder.append("Locale="); - builder.append(LocaleHelper.getLocale().toString()); - builder.append(";"); - - String url = builder.toString(); - - Properties properties = new Properties(); - properties.put("url", url); - properties.put("driver", MondrianOlap4jDriver.class.getName()); - - Logger logger = getLogger(); - if (logger.isInfoEnabled()) { - logger.info("Using connection URL : {}", url); - } - - List roleNames = null; - - if (roleMapper != null) { - try { - String[] roles = roleMapper.mapConnectionRoles(session, - definition.getName()); - - if (roles != null) { - roleNames = new LinkedList(); - - for (String role : roles) { - roleNames.add(role); - } - } - } catch (PentahoAccessControlException e) { - logger.warn("Unable to read assigned roles for the current user.", e); - } - } - - if (roleNames == null) { - roleNames = Collections.emptyList(); - } - - return new MdxOlap4JDataSource(session, properties, roleNames); - } + AbstractDataSourceManager { + + private IPentahoSession session; + + private IMondrianCatalogService catalogService; + + private IConnectionUserRoleMapper roleMapper; + + /** + * @see + * org.pivot4j.analytics.datasource.AbstractDataSourceManager#initialize() + */ + @Override + protected void initialize() { + this.session = PentahoSessionHolder.getSession(); + this.catalogService = PentahoSystem.get(IMondrianCatalogService.class, + session); + + if (PentahoSystem.getObjectFactory().objectDefined( + MDX_CONNECTION_MAPPER_KEY)) { + this.roleMapper = PentahoSystem.get( + IConnectionUserRoleMapper.class, MDX_CONNECTION_MAPPER_KEY, + null); + } + + super.initialize(); + } + + /** + * @see org.pivot4j.analytics.datasource.AbstractDataSourceManager#destroy() + */ + @Override + protected void destroy() { + this.session = null; + this.catalogService = null; + } + + /** + * @return the session + */ + protected IPentahoSession getSession() { + return session; + } + + /** + * @return the catalogService + */ + protected IMondrianCatalogService getCatalogService() { + return catalogService; + } + + /** + * @return the roleMapper + */ + protected IConnectionUserRoleMapper getRoleMapper() { + return roleMapper; + } + + /** + * @see org.pivot4j.analytics.datasource.DataSourceManager#getCatalogs() + */ + @Override + public List getCatalogs() { + List catalogs = catalogService.listCatalogs(session, + false); + + List result = new LinkedList(); + + for (MondrianCatalog catalog : catalogs) { + if (!getCubes(catalog.getName()).isEmpty()) { + result.add(new CatalogInfo(catalog.getName(), + catalog.getName(), catalog.getDefinition())); + } + } + + return result; + } + + /** + * @param name + * @return + */ + public MondrianCatalog getCatalog(String name) { + return catalogService.getCatalog(name, session); + } + + /** + * @see + * org.pivot4j.analytics.datasource.DataSourceManager#getCubes(java.lang.String) + */ + @Override + public List getCubes(String catalogName) { + if (catalogName == null) { + throw new NullArgumentException("catalogName"); + } + + List cubes = new LinkedList(); + + MondrianCatalog catalog = getCatalog(catalogName); + + if (catalog == null) { + throw new IllegalArgumentException( + "The catalog with the given name does not exist : " + + catalogName); + } + + OlapDataSource dataSource = createDataSource(new PentahoDataSourceDefinition( + catalog)); + OlapConnection con = null; + + try { + con = dataSource.getConnection(); + + List olapCubes = con.getOlapSchema().getCubes(); + + for (Cube cube : olapCubes) { + if (cube.isVisible()) { + cubes.add(new CubeInfo(cube.getName(), cube.getCaption(), + cube.getDescription())); + } + } + } catch (SQLException e) { + throw new UnhandledException(e); + } finally { + DbUtils.closeQuietly(con); + } + + return cubes; + } + + /** + * @see + * org.pivot4j.analytics.datasource.AbstractDataSourceManager#registerDefinitions() + */ + @Override + protected void registerDefinitions() { + List catalogs = catalogService.listCatalogs(session, + false); + + for (MondrianCatalog catalog : catalogs) { + registerDefinition(new PentahoDataSourceDefinition(catalog)); + } + } + + /** + * @see + * org.pivot4j.analytics.datasource.AbstractDataSourceManager#getDefinition(org.pivot4j.analytics.datasource.ConnectionInfo) + */ + @Override + protected synchronized PentahoDataSourceDefinition getDefinition( + ConnectionInfo connectionInfo) { + PentahoDataSourceDefinition definition = super + .getDefinition(connectionInfo); + + if (definition == null) { + MondrianCatalog catalog = catalogService.getCatalog( + connectionInfo.getCatalogName(), session); + + if (catalog != null) { + definition = new PentahoDataSourceDefinition(catalog); + registerDefinition(definition); + } + } + + return definition; + } + + /** + * @see + * org.pivot4j.analytics.datasource.AbstractDataSourceManager#createDataSourceDefinition(org.apache.commons.configuration.HierarchicalConfiguration) + */ + @Override + protected PentahoDataSourceDefinition createDataSourceDefinition( + HierarchicalConfiguration configuration) { + return null; + } + + /** + * @see + * org.pivot4j.analytics.datasource.AbstractDataSourceManager#createDataSource(org.pivot4j.analytics.datasource.DataSourceInfo) + */ + @Override + protected OlapDataSource createDataSource( + PentahoDataSourceDefinition definition) { + if (definition == null) { + return null; + } + + MondrianCatalog catalog = getCatalog(definition.getName()); + + if (catalog == null) { + Logger logger = getLogger(); + if (logger.isWarnEnabled()) { + logger.warn("Unable to find catalog with name : " + + definition.getName()); + } + + return null; + } + + Util.PropertyList parsedProperties = Util.parseConnectString(catalog + .getDataSourceInfo()); + + StringBuilder builder = new StringBuilder(); + builder.append("jdbc:mondrian:"); + builder.append("Catalog="); + builder.append(catalog.getDefinition()); + builder.append("; "); + + Iterator> it = parsedProperties.iterator(); + + while (it.hasNext()) { + Pair pair = it.next(); + builder.append(pair.getKey()); + builder.append("="); + builder.append(pair.getValue()); + builder.append("; "); + } + + builder.append("PoolNeeded=false; "); + builder.append("Locale="); + builder.append(LocaleHelper.getLocale().toString()); + builder.append(";"); + + String url = builder.toString(); + + Properties properties = new Properties(); + properties.put("url", url); + properties.put("driver", MondrianOlap4jDriver.class.getName()); + + Logger logger = getLogger(); + if (logger.isInfoEnabled()) { + logger.info("Using connection URL : {}", url); + } + + List roleNames = null; + + if (roleMapper != null) { + try { + String[] roles = roleMapper.mapConnectionRoles(session, + definition.getName()); + + if (roles != null) { + roleNames = new LinkedList(); + + for (String role : roles) { + roleNames.add(role); + } + } + } catch (PentahoAccessControlException e) { + logger.warn("Unable to read assigned roles for the current user.", e); + } + } + + if (roleNames == null) { + roleNames = Collections.emptyList(); + } + + return new MdxOlap4JDataSource(session, properties, roleNames); + } } diff --git a/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/repository/PentahoReportFile.java b/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/repository/PentahoReportFile.java index 2f88418b..1dfa7a8b 100644 --- a/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/repository/PentahoReportFile.java +++ b/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/repository/PentahoReportFile.java @@ -11,110 +11,110 @@ public class PentahoReportFile extends AbstractReportFile { - public static final String DEFAULT_EXTENSION = "pivot4j"; - - private RepositoryFile file; - - private PentahoReportFile parent; - - private boolean writeable; - - /** - * @param file - * @param parent - * @param writeable - */ - public PentahoReportFile(RepositoryFile file, PentahoReportFile parent, boolean writeable) { - if (file == null) { - throw new NullArgumentException("file"); - } - - this.file = file; - this.parent = parent; - this.writeable = writeable; - } - - /** - * @return the file - */ - protected RepositoryFile getFile() { - return file; - } - - /** - * @see org.pivot4j.analytics.repository.AbstractReportFile#getId() - */ - @Override - public Serializable getId() { - return file.getId(); - } - - /** - * @see org.pivot4j.analytics.repository.ReportFile#getName() - */ - @Override - public String getName() { - return file.getName(); - } - - public String getTitle() { - return file.getTitle(); - } - - /** - * @see org.pivot4j.analytics.repository.ReportFile#getPath() - */ - @Override - public String getPath() { - return file.getPath().replaceAll(RepositoryFile.SEPARATOR, - ReportFile.SEPARATOR); - } - - /** - * @see org.pivot4j.analytics.repository.ReportFile#getParent() - */ - @Override - public ReportFile getParent() throws IOException { - return parent; - } - - /** - * @see org.pivot4j.analytics.repository.ReportFile#isDirectory() - */ - @Override - public boolean isDirectory() { - return file.isFolder(); - } - - /** - * @see org.pivot4j.analytics.repository.ReportFile#getLastModifiedDate() - */ - @Override - public Date getLastModifiedDate() { - return file.getLastModifiedDate(); - } - - /** - * @see org.pivot4j.analytics.repository.ReportFile#getSize() - */ - @Override - public long getSize() { - return file.getFileSize(); - } - - /** - * @see org.pivot4j.analytics.repository.ReportFile#canRead() - */ - @Override - public boolean canRead() { - return true; - } - - /** - * @see org.pivot4j.analytics.repository.ReportFile#canWrite() - */ - @Override - public boolean canWrite() { - return writeable; - } + public static final String DEFAULT_EXTENSION = "pivot4j"; + + private RepositoryFile file; + + private PentahoReportFile parent; + + private boolean writeable; + + /** + * @param file + * @param parent + * @param writeable + */ + public PentahoReportFile(RepositoryFile file, PentahoReportFile parent, boolean writeable) { + if (file == null) { + throw new NullArgumentException("file"); + } + + this.file = file; + this.parent = parent; + this.writeable = writeable; + } + + /** + * @return the file + */ + protected RepositoryFile getFile() { + return file; + } + + /** + * @see org.pivot4j.analytics.repository.AbstractReportFile#getId() + */ + @Override + public Serializable getId() { + return file.getId(); + } + + /** + * @see org.pivot4j.analytics.repository.ReportFile#getName() + */ + @Override + public String getName() { + return file.getName(); + } + + public String getTitle() { + return file.getTitle(); + } + + /** + * @see org.pivot4j.analytics.repository.ReportFile#getPath() + */ + @Override + public String getPath() { + return file.getPath().replaceAll(RepositoryFile.SEPARATOR, + ReportFile.SEPARATOR); + } + + /** + * @see org.pivot4j.analytics.repository.ReportFile#getParent() + */ + @Override + public ReportFile getParent() throws IOException { + return parent; + } + + /** + * @see org.pivot4j.analytics.repository.ReportFile#isDirectory() + */ + @Override + public boolean isDirectory() { + return file.isFolder(); + } + + /** + * @see org.pivot4j.analytics.repository.ReportFile#getLastModifiedDate() + */ + @Override + public Date getLastModifiedDate() { + return file.getLastModifiedDate(); + } + + /** + * @see org.pivot4j.analytics.repository.ReportFile#getSize() + */ + @Override + public long getSize() { + return file.getFileSize(); + } + + /** + * @see org.pivot4j.analytics.repository.ReportFile#canRead() + */ + @Override + public boolean canRead() { + return true; + } + + /** + * @see org.pivot4j.analytics.repository.ReportFile#canWrite() + */ + @Override + public boolean canWrite() { + return writeable; + } } diff --git a/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/repository/PentahoReportRepository.java b/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/repository/PentahoReportRepository.java index 8d6f29f0..720a599e 100644 --- a/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/repository/PentahoReportRepository.java +++ b/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/repository/PentahoReportRepository.java @@ -32,307 +32,318 @@ public class PentahoReportRepository extends AbstractFileSystemRepository { - private IPentahoSession session; - - private IUnifiedRepository repository; - - @PostConstruct - protected void initialize() { - this.session = PentahoSessionHolder.getSession(); - this.repository = PentahoSystem.get(IUnifiedRepository.class, session); - } - - /** - * @return the session - */ - protected IPentahoSession getSession() { - return session; - } - - /** - * @return the repository - */ - protected IUnifiedRepository getRepository() { - return repository; - } - - /** - * @throws IOException - * @see org.pivot4j.analytics.repository.ReportRepository#getRoot() - */ - @Override - public PentahoReportFile getRoot() throws IOException { - return getFile(ReportFile.SEPARATOR); - } - - /** - * @see org.pivot4j.analytics.repository.ReportRepository#exists(java.lang.String) - */ - @Override - public boolean exists(String path) throws IOException { - return getFile(path) != null; - } - - /** - * @see org.pivot4j.analytics.repository.ReportRepository#fileWithIdExists(java.lang.String) - */ - @Override - public boolean fileWithIdExists(String id) throws IOException { - return repository.getFileById(id) != null; - } - - /** - * @see org.pivot4j.analytics.repository.ReportRepository#getFile(java.lang.String) - */ - @Override - public PentahoReportFile getFile(String path) throws IOException { - if (path == null) { - throw new NullArgumentException("path"); - } - - List segments = Arrays.asList(path.split(ReportFile.SEPARATOR)); - - List ancestors = new ArrayList( - segments.size()); - - ancestors.add(new PentahoReportFile(repository - .getFile(ReportFile.SEPARATOR), null, repository.hasAccess( - ReportFile.SEPARATOR, EnumSet.of(READ, WRITE)))); - - StringBuilder builder = new StringBuilder(); - - for (Object segment : segments) { - String name = segment.toString(); - - if (!name.isEmpty()) { - builder.append(name); - - RepositoryFile file = repository.getFile(builder.toString()); - - if (file == null) { - return null; - } - - ancestors.add(new PentahoReportFile(file, ancestors - .get(ancestors.size() - 1), repository.hasAccess( - file.getPath(), EnumSet.of(READ, WRITE)))); - } - - builder.append(ReportFile.SEPARATOR); - } - - return ancestors.get(ancestors.size() - 1); - } - - /** - * @see org.pivot4j.analytics.repository.ReportRepository#getFileById(java.lang.String) - */ - @Override - public PentahoReportFile getFileById(String id) throws IOException { - RepositoryFile file = repository.getFileById(id); - - if (file == null) { - return null; - } - - return getFile(file.getPath()); - } - - /** - * @see org.pivot4j.analytics.repository.ReportRepository#getFiles(org.pivot4j.analytics.repository.ReportFile) - */ - @Override - public List getFiles(ReportFile parent) throws IOException { - if (parent == null) { - throw new NullArgumentException("parent"); - } - - List files = new LinkedList(); - - if (parent.isDirectory()) { - List children = repository.getChildren(parent - .getId()); - - for (RepositoryFile file : children) { - boolean writeable = repository.hasAccess(file.getPath(), - EnumSet.of(READ, WRITE)); - - if (!parent.isRoot() || !file.getPath().equals("/etc")) { - files.add(new PentahoReportFile(file, - (PentahoReportFile) parent, writeable)); - } - } - } - - return files; - } - - /** - * @see org.pivot4j.analytics.repository.ReportRepository#createFile(org.pivot4j.analytics.repository.ReportFile, - * java.lang.String, org.pivot4j.analytics.repository.ReportContent) - */ - @Override - public ReportFile createFile(ReportFile parent, String name, - ReportContent content) throws IOException, ConfigurationException { - return createFile(parent, name, content, true); - } - - /** - * @param parent - * @param name - * @param content - * @param overwrite - * @return - * @throws IOException - * @throws ConfigurationException - */ - public ReportFile createFile(ReportFile parent, String name, - ReportContent content, boolean overwrite) throws IOException, - ConfigurationException { - if (parent == null) { - throw new NullArgumentException("parent"); - } - - if (name == null) { - throw new NullArgumentException("name"); - } - - if (content == null) { - throw new NullArgumentException("content"); - } - - RepositoryUtils utils = new RepositoryUtils(repository); - - StringBuilder builder = new StringBuilder(); - builder.append(parent.getPath()); - - if (!parent.getPath().endsWith(ReportFile.SEPARATOR)) { - builder.append(ReportFile.SEPARATOR); - } - - builder.append(name); - - RepositoryFile file = utils.saveFile(builder.toString(), - createReportData(content), true, overwrite, false, false, null); - - return new PentahoReportFile(file, (PentahoReportFile) parent, true); - } - - /** - * @see org.pivot4j.analytics.repository.ReportRepository#createDirectory(org.pivot4j.analytics.repository.ReportFile, - * java.lang.String) - */ - @Override - public ReportFile createDirectory(ReportFile parent, String name) - throws IOException { - if (parent == null) { - throw new NullArgumentException("parent"); - } - - if (name == null) { - throw new NullArgumentException("name"); - } - - RepositoryFile directory = new RepositoryFile.Builder(name) - .folder(true).build(); - directory = repository.createFolder(parent.getId(), directory, null); - - return new PentahoReportFile(directory, (PentahoReportFile) parent, - true); - } - - /** - * @see org.pivot4j.analytics.repository.ReportRepository#renameFile(org.pivot4j.analytics.repository.ReportFile, - * java.lang.String) - */ - @Override - public ReportFile renameFile(ReportFile file, String newName) - throws IOException { - if (file == null) { - throw new NullArgumentException("file"); - } - - if (newName == null) { - throw new NullArgumentException("newName"); - } - - String path = file.getParent().getPath() + ReportFile.SEPARATOR - + newName; - - repository.moveFile(file.getId(), path, null); - - return file; - } - - /** - * @see org.pivot4j.analytics.repository.ReportRepository#deleteFile(org.pivot4j.analytics.repository.ReportFile) - */ - @Override - public void deleteFile(ReportFile file) throws IOException { - if (file == null) { - throw new NullArgumentException("file"); - } - - repository.deleteFile(file.getId(), null); - } - - /** - * @see org.pivot4j.analytics.repository.ReportRepository#readContent(org.pivot4j.analytics.repository.ReportFile) - */ - @Override - public InputStream readContent(ReportFile file) throws IOException { - if (file == null) { - throw new NullArgumentException("file"); - } - - SimpleRepositoryFileData data = repository.getDataForRead(file.getId(), - SimpleRepositoryFileData.class); - - return data.getInputStream(); - } - - /** - * @see org.pivot4j.analytics.repository.ReportRepository#setReportContent(org.pivot4j.analytics.repository.ReportFile, - * org.pivot4j.analytics.repository.ReportContent) - */ - @Override - public void setReportContent(ReportFile file, ReportContent content) - throws IOException, ConfigurationException { - if (file == null) { - throw new NullArgumentException("file"); - } - - if (content == null) { - throw new NullArgumentException("content"); - } - - PentahoReportFile pentahoFile = (PentahoReportFile) file; - - ByteArrayOutputStream out = new ByteArrayOutputStream(); - content.write(out); - - out.flush(); - out.close(); - - repository.updateFile(pentahoFile.getFile(), createReportData(content), - null); - } - - /** - * @param content - * @return - * @throws ConfigurationException - * @throws IOException - */ - protected IRepositoryFileData createReportData(ReportContent content) - throws ConfigurationException, IOException { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - content.write(out); - - out.flush(); - out.close(); - - return new SimpleRepositoryFileData(new ByteArrayInputStream( - out.toByteArray()), "UTF-8", "text/xml"); - } + private IPentahoSession session; + + private IUnifiedRepository repository; + + @PostConstruct + protected void initialize() { + this.session = PentahoSessionHolder.getSession(); + this.repository = PentahoSystem.get(IUnifiedRepository.class, session); + } + + /** + * @return the session + */ + protected IPentahoSession getSession() { + return session; + } + + /** + * @return the repository + */ + protected IUnifiedRepository getRepository() { + return repository; + } + + /** + * @throws IOException + * @see org.pivot4j.analytics.repository.ReportRepository#getRoot() + */ + @Override + public PentahoReportFile getRoot() throws IOException { + return getFile(ReportFile.SEPARATOR); + } + + /** + * @see + * org.pivot4j.analytics.repository.ReportRepository#exists(java.lang.String) + */ + @Override + public boolean exists(String path) throws IOException { + return getFile(path) != null; + } + + /** + * @see + * org.pivot4j.analytics.repository.ReportRepository#fileWithIdExists(java.lang.String) + */ + @Override + public boolean fileWithIdExists(String id) throws IOException { + return repository.getFileById(id) != null; + } + + /** + * @see + * org.pivot4j.analytics.repository.ReportRepository#getFile(java.lang.String) + */ + @Override + public PentahoReportFile getFile(String path) throws IOException { + if (path == null) { + throw new NullArgumentException("path"); + } + + List segments = Arrays.asList(path.split(ReportFile.SEPARATOR)); + + List ancestors = new ArrayList( + segments.size()); + + ancestors.add(new PentahoReportFile(repository + .getFile(ReportFile.SEPARATOR), null, repository.hasAccess( + ReportFile.SEPARATOR, EnumSet.of(READ, WRITE)))); + + StringBuilder builder = new StringBuilder(); + + for (Object segment : segments) { + String name = segment.toString(); + + if (!name.isEmpty()) { + builder.append(name); + + RepositoryFile file = repository.getFile(builder.toString()); + + if (file == null) { + return null; + } + + ancestors.add(new PentahoReportFile(file, ancestors + .get(ancestors.size() - 1), repository.hasAccess( + file.getPath(), EnumSet.of(READ, WRITE)))); + } + + builder.append(ReportFile.SEPARATOR); + } + + return ancestors.get(ancestors.size() - 1); + } + + /** + * @see + * org.pivot4j.analytics.repository.ReportRepository#getFileById(java.lang.String) + */ + @Override + public PentahoReportFile getFileById(String id) throws IOException { + RepositoryFile file = repository.getFileById(id); + + if (file == null) { + return null; + } + + return getFile(file.getPath()); + } + + /** + * @see + * org.pivot4j.analytics.repository.ReportRepository#getFiles(org.pivot4j.analytics.repository.ReportFile) + */ + @Override + public List getFiles(ReportFile parent) throws IOException { + if (parent == null) { + throw new NullArgumentException("parent"); + } + + List files = new LinkedList(); + + if (parent.isDirectory()) { + List children = repository.getChildren(parent + .getId()); + + for (RepositoryFile file : children) { + boolean writeable = repository.hasAccess(file.getPath(), + EnumSet.of(READ, WRITE)); + + if (!parent.isRoot() || !file.getPath().equals("/etc")) { + files.add(new PentahoReportFile(file, + (PentahoReportFile) parent, writeable)); + } + } + } + + return files; + } + + /** + * @see + * org.pivot4j.analytics.repository.ReportRepository#createFile(org.pivot4j.analytics.repository.ReportFile, + * java.lang.String, org.pivot4j.analytics.repository.ReportContent) + */ + @Override + public ReportFile createFile(ReportFile parent, String name, + ReportContent content) throws IOException, ConfigurationException { + return createFile(parent, name, content, true); + } + + /** + * @param parent + * @param name + * @param content + * @param overwrite + * @return + * @throws IOException + * @throws ConfigurationException + */ + public ReportFile createFile(ReportFile parent, String name, + ReportContent content, boolean overwrite) throws IOException, + ConfigurationException { + if (parent == null) { + throw new NullArgumentException("parent"); + } + + if (name == null) { + throw new NullArgumentException("name"); + } + + if (content == null) { + throw new NullArgumentException("content"); + } + + RepositoryUtils utils = new RepositoryUtils(repository); + + StringBuilder builder = new StringBuilder(); + builder.append(parent.getPath()); + + if (!parent.getPath().endsWith(ReportFile.SEPARATOR)) { + builder.append(ReportFile.SEPARATOR); + } + + builder.append(name); + + RepositoryFile file = utils.saveFile(builder.toString(), + createReportData(content), true, overwrite, false, false, null); + + return new PentahoReportFile(file, (PentahoReportFile) parent, true); + } + + /** + * @see + * org.pivot4j.analytics.repository.ReportRepository#createDirectory(org.pivot4j.analytics.repository.ReportFile, + * java.lang.String) + */ + @Override + public ReportFile createDirectory(ReportFile parent, String name) + throws IOException { + if (parent == null) { + throw new NullArgumentException("parent"); + } + + if (name == null) { + throw new NullArgumentException("name"); + } + + RepositoryFile directory = new RepositoryFile.Builder(name) + .folder(true).build(); + directory = repository.createFolder(parent.getId(), directory, null); + + return new PentahoReportFile(directory, (PentahoReportFile) parent, + true); + } + + /** + * @see + * org.pivot4j.analytics.repository.ReportRepository#renameFile(org.pivot4j.analytics.repository.ReportFile, + * java.lang.String) + */ + @Override + public ReportFile renameFile(ReportFile file, String newName) + throws IOException { + if (file == null) { + throw new NullArgumentException("file"); + } + + if (newName == null) { + throw new NullArgumentException("newName"); + } + + String path = file.getParent().getPath() + ReportFile.SEPARATOR + + newName; + + repository.moveFile(file.getId(), path, null); + + return file; + } + + /** + * @see + * org.pivot4j.analytics.repository.ReportRepository#deleteFile(org.pivot4j.analytics.repository.ReportFile) + */ + @Override + public void deleteFile(ReportFile file) throws IOException { + if (file == null) { + throw new NullArgumentException("file"); + } + + repository.deleteFile(file.getId(), null); + } + + /** + * @see + * org.pivot4j.analytics.repository.ReportRepository#readContent(org.pivot4j.analytics.repository.ReportFile) + */ + @Override + public InputStream readContent(ReportFile file) throws IOException { + if (file == null) { + throw new NullArgumentException("file"); + } + + SimpleRepositoryFileData data = repository.getDataForRead(file.getId(), + SimpleRepositoryFileData.class); + + return data.getInputStream(); + } + + /** + * @see + * org.pivot4j.analytics.repository.ReportRepository#setReportContent(org.pivot4j.analytics.repository.ReportFile, + * org.pivot4j.analytics.repository.ReportContent) + */ + @Override + public void setReportContent(ReportFile file, ReportContent content) + throws IOException, ConfigurationException { + if (file == null) { + throw new NullArgumentException("file"); + } + + if (content == null) { + throw new NullArgumentException("content"); + } + + PentahoReportFile pentahoFile = (PentahoReportFile) file; + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + content.write(out); + + out.flush(); + out.close(); + + repository.updateFile(pentahoFile.getFile(), createReportData(content), + null); + } + + /** + * @param content + * @return + * @throws ConfigurationException + * @throws IOException + */ + protected IRepositoryFileData createReportData(ReportContent content) + throws ConfigurationException, IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + content.write(out); + + out.flush(); + out.close(); + + return new SimpleRepositoryFileData(new ByteArrayInputStream( + out.toByteArray()), "UTF-8", "text/xml"); + } } diff --git a/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/servlet/FacesDispatcherServlet.java b/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/servlet/FacesDispatcherServlet.java index d8df3c51..cdde0b0c 100644 --- a/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/servlet/FacesDispatcherServlet.java +++ b/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/servlet/FacesDispatcherServlet.java @@ -14,107 +14,106 @@ public class FacesDispatcherServlet extends HttpServlet { - private static final long serialVersionUID = 9009308748116185472L; - - private FacesServlet facesServlet; - - private PluginServletContext contextWrapper; - - private Map initParameters; - - /** - * @return the initParameters - */ - public Map getInitParameters() { - return initParameters; - } - - /** - * @param initParameters - * the initParameters to set - */ - public void setInitParameters(Map initParameters) { - this.initParameters = initParameters; - } - - /** - * @return the contextListener - */ - protected PluginServletContext getContextWrapper() { - return contextWrapper; - } - - /** - * @return facesServlet - */ - protected FacesServlet getFacesServlet() { - return facesServlet; - } - - /** - * @see javax.servlet.GenericServlet#init(javax.servlet.ServletConfig) - */ - @Override - public void init(ServletConfig config) throws ServletException { - super.init(config); - - if (initParameters == null) { - this.initParameters = new HashMap(); - } - - ClassLoader loader = Thread.currentThread().getContextClassLoader(); - - try { - Thread.currentThread().setContextClassLoader( - getClass().getClassLoader()); - - this.contextWrapper = new PluginServletContext( - config.getServletContext(), initParameters); - contextWrapper.initialize(); - - this.facesServlet = new FacesServlet(); - this.facesServlet.init(new PluginServletConfig(contextWrapper)); - } finally { - Thread.currentThread().setContextClassLoader(loader); - } - } - - /** - * @see javax.servlet.GenericServlet#destroy() - */ - @Override - public void destroy() { - this.contextWrapper.destroy(); - this.contextWrapper = null; - - this.facesServlet.destroy(); - this.facesServlet = null; - - super.destroy(); - } - - /** - * @see javax.servlet.http.HttpServlet#service(javax.servlet.ServletRequest, - * javax.servlet.ServletResponse) - */ - @Override - public void service(ServletRequest request, ServletResponse response) - throws ServletException, IOException { - ClassLoader loader = Thread.currentThread().getContextClassLoader(); - - PluginServletRequest wrappedRequest = new PluginServletRequest( - contextWrapper, (HttpServletRequest) request); - try { - Thread.currentThread().setContextClassLoader( - getClass().getClassLoader()); - - wrappedRequest.initialize(); - - facesServlet.service(wrappedRequest, response); - } finally { - Thread.currentThread().setContextClassLoader(loader); - - wrappedRequest.destroy(); - } - } -} \ No newline at end of file + private static final long serialVersionUID = 9009308748116185472L; + + private FacesServlet facesServlet; + + private PluginServletContext contextWrapper; + + private Map initParameters; + + /** + * @return the initParameters + */ + public Map getInitParameters() { + return initParameters; + } + + /** + * @param initParameters the initParameters to set + */ + public void setInitParameters(Map initParameters) { + this.initParameters = initParameters; + } + + /** + * @return the contextListener + */ + protected PluginServletContext getContextWrapper() { + return contextWrapper; + } + + /** + * @return facesServlet + */ + protected FacesServlet getFacesServlet() { + return facesServlet; + } + + /** + * @see javax.servlet.GenericServlet#init(javax.servlet.ServletConfig) + */ + @Override + public void init(ServletConfig config) throws ServletException { + super.init(config); + + if (initParameters == null) { + this.initParameters = new HashMap(); + } + + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + + try { + Thread.currentThread().setContextClassLoader( + getClass().getClassLoader()); + + this.contextWrapper = new PluginServletContext( + config.getServletContext(), initParameters); + contextWrapper.initialize(); + + this.facesServlet = new FacesServlet(); + this.facesServlet.init(new PluginServletConfig(contextWrapper)); + } finally { + Thread.currentThread().setContextClassLoader(loader); + } + } + + /** + * @see javax.servlet.GenericServlet#destroy() + */ + @Override + public void destroy() { + this.contextWrapper.destroy(); + this.contextWrapper = null; + + this.facesServlet.destroy(); + this.facesServlet = null; + + super.destroy(); + } + + /** + * @see javax.servlet.http.HttpServlet#service(javax.servlet.ServletRequest, + * javax.servlet.ServletResponse) + */ + @Override + public void service(ServletRequest request, ServletResponse response) + throws ServletException, IOException { + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + + PluginServletRequest wrappedRequest = new PluginServletRequest( + contextWrapper, (HttpServletRequest) request); + try { + Thread.currentThread().setContextClassLoader( + getClass().getClassLoader()); + + wrappedRequest.initialize(); + + facesServlet.service(wrappedRequest, response); + } finally { + Thread.currentThread().setContextClassLoader(loader); + + wrappedRequest.destroy(); + } + } +} diff --git a/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/servlet/PluginResourceResolver.java b/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/servlet/PluginResourceResolver.java index 059894f2..f50317f7 100644 --- a/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/servlet/PluginResourceResolver.java +++ b/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/servlet/PluginResourceResolver.java @@ -6,13 +6,14 @@ public class PluginResourceResolver extends DefaultResourceResolver { - public static final String RESOURCE_PREFIX = "./webapp"; + public static final String RESOURCE_PREFIX = "./webapp"; - /** - * @see org.apache.myfaces.view.facelets.impl.DefaultResourceResolver#resolveUrl(java.lang.String) - */ - @Override - public URL resolveUrl(String path) { - return getClass().getClassLoader().getResource(RESOURCE_PREFIX + path); - } + /** + * @see + * org.apache.myfaces.view.facelets.impl.DefaultResourceResolver#resolveUrl(java.lang.String) + */ + @Override + public URL resolveUrl(String path) { + return getClass().getClassLoader().getResource(RESOURCE_PREFIX + path); + } } diff --git a/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/servlet/PluginServletConfig.java b/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/servlet/PluginServletConfig.java index 13462fa1..66478864 100644 --- a/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/servlet/PluginServletConfig.java +++ b/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/servlet/PluginServletConfig.java @@ -7,46 +7,46 @@ public class PluginServletConfig implements ServletConfig { - public static final String SERVLET_NAME = "facesServlet"; - - private ServletContext context; - - /** - * @param context - */ - public PluginServletConfig(ServletContext context) { - this.context = context; - } - - /** - * @see javax.servlet.ServletConfig#getInitParameter(java.lang.String) - */ - @Override - public String getInitParameter(String name) { - return context.getInitParameter(name); - } - - /** - * @see javax.servlet.ServletConfig#getInitParameterNames() - */ - @Override - public Enumeration getInitParameterNames() { - return context.getInitParameterNames(); - } - - /** - * @see javax.servlet.ServletConfig#getServletContext() - */ - @Override - public ServletContext getServletContext() { - return context; - } - - /** - * @see javax.servlet.ServletConfig#getServletName() - */ - @Override - public String getServletName() { - return SERVLET_NAME; - } + public static final String SERVLET_NAME = "facesServlet"; + + private ServletContext context; + + /** + * @param context + */ + public PluginServletConfig(ServletContext context) { + this.context = context; + } + + /** + * @see javax.servlet.ServletConfig#getInitParameter(java.lang.String) + */ + @Override + public String getInitParameter(String name) { + return context.getInitParameter(name); + } + + /** + * @see javax.servlet.ServletConfig#getInitParameterNames() + */ + @Override + public Enumeration getInitParameterNames() { + return context.getInitParameterNames(); + } + + /** + * @see javax.servlet.ServletConfig#getServletContext() + */ + @Override + public ServletContext getServletContext() { + return context; + } + + /** + * @see javax.servlet.ServletConfig#getServletName() + */ + @Override + public String getServletName() { + return SERVLET_NAME; + } } diff --git a/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/servlet/PluginServletContext.java b/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/servlet/PluginServletContext.java index 699950f5..065b9262 100644 --- a/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/servlet/PluginServletContext.java +++ b/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/servlet/PluginServletContext.java @@ -18,450 +18,440 @@ public class PluginServletContext implements ServletContext { - private ServletContext wrappedContext; - - private StartupServletContextListener listener; - - private Map initParameters; - - private ResourceResolver resourceResolver; - - /** - * @param context - * @param initParameters - */ - public PluginServletContext(ServletContext context, - Map initParameters) { - this.wrappedContext = context; - this.initParameters = initParameters; - - this.listener = new StartupServletContextListener(); - this.resourceResolver = new PluginResourceResolver(); - } - - /** - * @return the wrappedContext - */ - protected ServletContext getWrappedContext() { - return wrappedContext; - } - - /** - * @return the resourceResolver - */ - protected ResourceResolver getResourceResolver() { - return resourceResolver; - } - - /** - * @return the listener - */ - public StartupServletContextListener getListener() { - return listener; - } - - public void initialize() { - setAttribute("org.apache.myfaces.DYNAMICALLY_ADDED_FACES_SERVLET", true); - - listener.contextInitialized(new ServletContextEvent(this)); - } - - public void destroy() { - listener.contextDestroyed(new ServletContextEvent(this)); - } - - /** - * @param name - * @return - * @see javax.servlet.ServletContext#getAttribute(java.lang.String) - */ - public Object getAttribute(String name) { - return wrappedContext.getAttribute(name); - } - - /** - * @return - * @see javax.servlet.ServletContext#getAttributeNames() - */ - public Enumeration getAttributeNames() { - return wrappedContext.getAttributeNames(); - } - - /** - * @param uripath - * @return - * @see javax.servlet.ServletContext#getContext(java.lang.String) - */ - public ServletContext getContext(String uripath) { - return wrappedContext.getContext(uripath); - } - - /** - * @return - */ - public String getContextPath() { - return wrappedContext.getContextPath(); - } - - /** - * @param name - * @return - * @see javax.servlet.ServletContext#getInitParameter(java.lang.String) - */ - public String getInitParameter(String name) { - if (initParameters != null && initParameters.containsKey(name)) { - return initParameters.get(name); - } - - return wrappedContext.getInitParameter(name); - } - - /** - * @return - * @see javax.servlet.ServletContext#getInitParameterNames() - */ - public Enumeration getInitParameterNames() { - Enumeration e = wrappedContext.getInitParameterNames(); - - if (initParameters == null) { - return e; - } - - List names = new LinkedList(); - - for (String name : initParameters.keySet()) { - names.add(name); - } - - while (e.hasMoreElements()) { - names.add(e.nextElement().toString()); - } - - return Collections.enumeration(names); - } - - @Override - public boolean setInitParameter(String name, String value) { - return false; - } - - /** - * @return - * @see javax.servlet.ServletContext#getMajorVersion() - */ - public int getMajorVersion() { - return wrappedContext.getMajorVersion(); - } - - /** - * @return - * @see javax.servlet.ServletContext#getMinorVersion() - */ - public int getMinorVersion() { - return wrappedContext.getMinorVersion(); - } - - @Override - public int getEffectiveMajorVersion() { - return 0; - } - - @Override - public int getEffectiveMinorVersion() { - return 0; - } - - /** - * @param file - * @return - * @see javax.servlet.ServletContext#getMimeType(java.lang.String) - */ - public String getMimeType(String file) { - return wrappedContext.getMimeType(file); - } - - /** - * @param name - * @return - * @see javax.servlet.ServletContext#getNamedDispatcher(java.lang.String) - */ - public RequestDispatcher getNamedDispatcher(String name) { - return wrappedContext.getNamedDispatcher(name); - } - - /** - * @param path - * @return - * @see javax.servlet.ServletContext#getRealPath(java.lang.String) - */ - public String getRealPath(String path) { - return wrappedContext.getRealPath(path); - } - - /** - * @param path - * @return - * @see javax.servlet.ServletContext#getRequestDispatcher(java.lang.String) - */ - public RequestDispatcher getRequestDispatcher(String path) { - return wrappedContext.getRequestDispatcher(path); - } - - /** - * @param path - * @return - * @throws MalformedURLException - * @see javax.servlet.ServletContext#getResource(java.lang.String) - */ - public URL getResource(String path) throws MalformedURLException { - return resourceResolver.resolveUrl(path); - } - - /** - * @param path - * @return - * @see javax.servlet.ServletContext#getResourceAsStream(java.lang.String) - */ - public InputStream getResourceAsStream(String path) { - InputStream in = null; - - try { - URL url = getResource(path); - - if (url != null) { - in = url.openStream(); - } - } catch (IOException e) { - throw new UnhandledException(e); - } - - return in; - } - - /** - * @param path - * @return - * @see javax.servlet.ServletContext#getResourcePaths(java.lang.String) - */ - public Set getResourcePaths(String path) { - return wrappedContext.getResourcePaths(path); - } - - /** - * @return - * @see javax.servlet.ServletContext#getServerInfo() - */ - public String getServerInfo() { - return wrappedContext.getServerInfo(); - } - - /** - * @param name - * @return - * @throws ServletException - * @deprecated - * @see javax.servlet.ServletContext#getServlet(java.lang.String) - */ - public Servlet getServlet(String name) throws ServletException { - return wrappedContext.getServlet(name); - } - - /** - * @return - * @see javax.servlet.ServletContext#getServletContextName() - */ - public String getServletContextName() { - return wrappedContext.getServletContextName(); - } - - @Override - public ServletRegistration.Dynamic addServlet(String servletName, String className) { - return null; - } - - @Override - public ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet) { - return null; - } - - @Override - public ServletRegistration.Dynamic addServlet(String servletName, Class servletClass) { - return null; - } - - @Override - public T createServlet(Class clazz) throws ServletException { - return null; - } - - @Override - public ServletRegistration getServletRegistration(String servletName) { - return null; - } - - @Override - public Map getServletRegistrations() { - return null; - } - - @Override - public FilterRegistration.Dynamic addFilter(String filterName, String className) { - return null; - } - - @Override - public FilterRegistration.Dynamic addFilter(String filterName, Filter filter) { - return null; - } - - @Override - public FilterRegistration.Dynamic addFilter(String filterName, Class filterClass) { - return null; - } - - @Override - public T createFilter(Class clazz) throws ServletException { - return null; - } - - @Override - public FilterRegistration getFilterRegistration(String filterName) { - return null; - } - - @Override - public Map getFilterRegistrations() { - return null; - } - - @Override - public SessionCookieConfig getSessionCookieConfig() { - return null; - } - - @Override - public void setSessionTrackingModes(Set sessionTrackingModes) { - } - - @Override - public Set getDefaultSessionTrackingModes() { - return null; - } - - @Override - public Set getEffectiveSessionTrackingModes() { - return null; - } - - @Override - public void addListener(String className) { - } - - @Override - public void addListener(T t) { - } - - @Override - public void addListener(Class listenerClass) { - - } - - @Override - public T createListener(Class clazz) throws ServletException { - return null; - } - - @Override - public JspConfigDescriptor getJspConfigDescriptor() { - return null; - } - - @Override - public ClassLoader getClassLoader() { - return null; - } - - @Override - public void declareRoles(String... roleNames) { - } - - /** - * @return - * @deprecated - * @see javax.servlet.ServletContext#getServletNames() - */ - public Enumeration getServletNames() { - return wrappedContext.getServletNames(); - } - - /** - * @return - * @deprecated - * @see javax.servlet.ServletContext#getServlets() - */ - public Enumeration getServlets() { - return wrappedContext.getServlets(); - } - - /** - * @param throwable - * @param msg - * @deprecated - * @see javax.servlet.ServletContext#log(java.lang.Exception, - * java.lang.String) - */ - public void log(Exception throwable, String msg) { - wrappedContext.log(throwable, msg); - } - - /** - * @param msg - * @param throwable - * @see javax.servlet.ServletContext#log(java.lang.String, - * java.lang.Throwable) - */ - public void log(String msg, Throwable throwable) { - wrappedContext.log(msg, throwable); - } - - /** - * @param msg - * @see javax.servlet.ServletContext#log(java.lang.String) - */ - public void log(String msg) { - wrappedContext.log(msg); - } - - /** - * @param name - * @see javax.servlet.ServletContext#removeAttribute(java.lang.String) - */ - public void removeAttribute(String name) { - Object value = getAttribute(name); - - wrappedContext.removeAttribute(name); - - listener.attributeRemoved(new ServletContextAttributeEvent(this, name, - value)); - } - - /** - * @param name - * @param value - * @see javax.servlet.ServletContext#setAttribute(java.lang.String, - * java.lang.Object) - */ - public void setAttribute(String name, Object value) { - Object oldValue = getAttribute(name); - - wrappedContext.setAttribute(name, value); - - if (oldValue == null) { - listener.attributeAdded(new ServletContextAttributeEvent(this, - name, value)); - } else if (!ObjectUtils.equals(oldValue, value)) { - listener.attributeReplaced(new ServletContextAttributeEvent(this, - name, value)); - } - } + private ServletContext wrappedContext; + + private StartupServletContextListener listener; + + private Map initParameters; + + private ResourceResolver resourceResolver; + + /** + * @param context + * @param initParameters + */ + public PluginServletContext(ServletContext context, + Map initParameters) { + this.wrappedContext = context; + this.initParameters = initParameters; + + this.listener = new StartupServletContextListener(); + this.resourceResolver = new PluginResourceResolver(); + } + + /** + * @return the wrappedContext + */ + protected ServletContext getWrappedContext() { + return wrappedContext; + } + + /** + * @return the resourceResolver + */ + protected ResourceResolver getResourceResolver() { + return resourceResolver; + } + + /** + * @return the listener + */ + public StartupServletContextListener getListener() { + return listener; + } + + public void initialize() { + setAttribute("org.apache.myfaces.DYNAMICALLY_ADDED_FACES_SERVLET", true); + + listener.contextInitialized(new ServletContextEvent(this)); + } + + public void destroy() { + listener.contextDestroyed(new ServletContextEvent(this)); + } + + /** + * @param name + * @return + * @see javax.servlet.ServletContext#getAttribute(java.lang.String) + */ + public Object getAttribute(String name) { + return wrappedContext.getAttribute(name); + } + + /** + * @return @see javax.servlet.ServletContext#getAttributeNames() + */ + public Enumeration getAttributeNames() { + return wrappedContext.getAttributeNames(); + } + + /** + * @param uripath + * @return + * @see javax.servlet.ServletContext#getContext(java.lang.String) + */ + public ServletContext getContext(String uripath) { + return wrappedContext.getContext(uripath); + } + + /** + * @return + */ + public String getContextPath() { + return wrappedContext.getContextPath(); + } + + /** + * @param name + * @return + * @see javax.servlet.ServletContext#getInitParameter(java.lang.String) + */ + public String getInitParameter(String name) { + if (initParameters != null && initParameters.containsKey(name)) { + return initParameters.get(name); + } + + return wrappedContext.getInitParameter(name); + } + + /** + * @return @see javax.servlet.ServletContext#getInitParameterNames() + */ + public Enumeration getInitParameterNames() { + Enumeration e = wrappedContext.getInitParameterNames(); + + if (initParameters == null) { + return e; + } + + List names = new LinkedList(); + + for (String name : initParameters.keySet()) { + names.add(name); + } + + while (e.hasMoreElements()) { + names.add(e.nextElement().toString()); + } + + return Collections.enumeration(names); + } + + @Override + public boolean setInitParameter(String name, String value) { + return false; + } + + /** + * @return @see javax.servlet.ServletContext#getMajorVersion() + */ + public int getMajorVersion() { + return wrappedContext.getMajorVersion(); + } + + /** + * @return @see javax.servlet.ServletContext#getMinorVersion() + */ + public int getMinorVersion() { + return wrappedContext.getMinorVersion(); + } + + @Override + public int getEffectiveMajorVersion() { + return 0; + } + + @Override + public int getEffectiveMinorVersion() { + return 0; + } + + /** + * @param file + * @return + * @see javax.servlet.ServletContext#getMimeType(java.lang.String) + */ + public String getMimeType(String file) { + return wrappedContext.getMimeType(file); + } + + /** + * @param name + * @return + * @see javax.servlet.ServletContext#getNamedDispatcher(java.lang.String) + */ + public RequestDispatcher getNamedDispatcher(String name) { + return wrappedContext.getNamedDispatcher(name); + } + + /** + * @param path + * @return + * @see javax.servlet.ServletContext#getRealPath(java.lang.String) + */ + public String getRealPath(String path) { + return wrappedContext.getRealPath(path); + } + + /** + * @param path + * @return + * @see javax.servlet.ServletContext#getRequestDispatcher(java.lang.String) + */ + public RequestDispatcher getRequestDispatcher(String path) { + return wrappedContext.getRequestDispatcher(path); + } + + /** + * @param path + * @return + * @throws MalformedURLException + * @see javax.servlet.ServletContext#getResource(java.lang.String) + */ + public URL getResource(String path) throws MalformedURLException { + return resourceResolver.resolveUrl(path); + } + + /** + * @param path + * @return + * @see javax.servlet.ServletContext#getResourceAsStream(java.lang.String) + */ + public InputStream getResourceAsStream(String path) { + InputStream in = null; + + try { + URL url = getResource(path); + + if (url != null) { + in = url.openStream(); + } + } catch (IOException e) { + throw new UnhandledException(e); + } + + return in; + } + + /** + * @param path + * @return + * @see javax.servlet.ServletContext#getResourcePaths(java.lang.String) + */ + public Set getResourcePaths(String path) { + return wrappedContext.getResourcePaths(path); + } + + /** + * @return @see javax.servlet.ServletContext#getServerInfo() + */ + public String getServerInfo() { + return wrappedContext.getServerInfo(); + } + + /** + * @param name + * @return + * @throws ServletException + * @deprecated + * @see javax.servlet.ServletContext#getServlet(java.lang.String) + */ + public Servlet getServlet(String name) throws ServletException { + return wrappedContext.getServlet(name); + } + + /** + * @return @see javax.servlet.ServletContext#getServletContextName() + */ + public String getServletContextName() { + return wrappedContext.getServletContextName(); + } + + @Override + public ServletRegistration.Dynamic addServlet(String servletName, String className) { + return null; + } + + @Override + public ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet) { + return null; + } + + @Override + public ServletRegistration.Dynamic addServlet(String servletName, Class servletClass) { + return null; + } + + @Override + public T createServlet(Class clazz) throws ServletException { + return null; + } + + @Override + public ServletRegistration getServletRegistration(String servletName) { + return null; + } + + @Override + public Map getServletRegistrations() { + return null; + } + + @Override + public FilterRegistration.Dynamic addFilter(String filterName, String className) { + return null; + } + + @Override + public FilterRegistration.Dynamic addFilter(String filterName, Filter filter) { + return null; + } + + @Override + public FilterRegistration.Dynamic addFilter(String filterName, Class filterClass) { + return null; + } + + @Override + public T createFilter(Class clazz) throws ServletException { + return null; + } + + @Override + public FilterRegistration getFilterRegistration(String filterName) { + return null; + } + + @Override + public Map getFilterRegistrations() { + return null; + } + + @Override + public SessionCookieConfig getSessionCookieConfig() { + return null; + } + + @Override + public void setSessionTrackingModes(Set sessionTrackingModes) { + } + + @Override + public Set getDefaultSessionTrackingModes() { + return null; + } + + @Override + public Set getEffectiveSessionTrackingModes() { + return null; + } + + @Override + public void addListener(String className) { + } + + @Override + public void addListener(T t) { + } + + @Override + public void addListener(Class listenerClass) { + + } + + @Override + public T createListener(Class clazz) throws ServletException { + return null; + } + + @Override + public JspConfigDescriptor getJspConfigDescriptor() { + return null; + } + + @Override + public ClassLoader getClassLoader() { + return null; + } + + @Override + public void declareRoles(String... roleNames) { + } + + /** + * @return @deprecated @see javax.servlet.ServletContext#getServletNames() + */ + public Enumeration getServletNames() { + return wrappedContext.getServletNames(); + } + + /** + * @return @deprecated @see javax.servlet.ServletContext#getServlets() + */ + public Enumeration getServlets() { + return wrappedContext.getServlets(); + } + + /** + * @param throwable + * @param msg + * @deprecated + * @see javax.servlet.ServletContext#log(java.lang.Exception, + * java.lang.String) + */ + public void log(Exception throwable, String msg) { + wrappedContext.log(throwable, msg); + } + + /** + * @param msg + * @param throwable + * @see javax.servlet.ServletContext#log(java.lang.String, + * java.lang.Throwable) + */ + public void log(String msg, Throwable throwable) { + wrappedContext.log(msg, throwable); + } + + /** + * @param msg + * @see javax.servlet.ServletContext#log(java.lang.String) + */ + public void log(String msg) { + wrappedContext.log(msg); + } + + /** + * @param name + * @see javax.servlet.ServletContext#removeAttribute(java.lang.String) + */ + public void removeAttribute(String name) { + Object value = getAttribute(name); + + wrappedContext.removeAttribute(name); + + listener.attributeRemoved(new ServletContextAttributeEvent(this, name, + value)); + } + + /** + * @param name + * @param value + * @see javax.servlet.ServletContext#setAttribute(java.lang.String, + * java.lang.Object) + */ + public void setAttribute(String name, Object value) { + Object oldValue = getAttribute(name); + + wrappedContext.setAttribute(name, value); + + if (oldValue == null) { + listener.attributeAdded(new ServletContextAttributeEvent(this, + name, value)); + } else if (!ObjectUtils.equals(oldValue, value)) { + listener.attributeReplaced(new ServletContextAttributeEvent(this, + name, value)); + } + } } diff --git a/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/servlet/PluginServletRequest.java b/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/servlet/PluginServletRequest.java index ff44b870..f0832ccd 100644 --- a/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/servlet/PluginServletRequest.java +++ b/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/servlet/PluginServletRequest.java @@ -11,123 +11,124 @@ public class PluginServletRequest extends HttpServletRequestWrapper { - public static final String PLUGIN_PREFIX = "/plugin"; - - public static final String SERVLET_PATH = "/pivot4j/faces"; - - private PluginServletContext servletContext; - - /** - * @param servletContext - * @param request - */ - public PluginServletRequest(PluginServletContext servletContext, - HttpServletRequest request) { - super(request); - - this.servletContext = servletContext; - } - - /** - * @return the servletContext - */ - public PluginServletContext getServletContext() { - return servletContext; - } - - public void initialize() { - StartupServletContextListener listener = servletContext.getListener(); - listener.requestInitialized(new ServletRequestEvent(servletContext, - this)); - } - - public void destroy() { - StartupServletContextListener listener = servletContext.getListener(); - listener.requestDestroyed(new ServletRequestEvent(servletContext, this)); - } - - /** - * @see javax.servlet.http.HttpServletRequestWrapper#getServletPath() - */ - @Override - public String getServletPath() { - return PLUGIN_PREFIX + SERVLET_PATH; - } - - /** - * @see javax.servlet.http.HttpServletRequestWrapper#getPathInfo() - */ - @Override - public String getPathInfo() { - String pathInfo = super.getPathInfo(); - - if (pathInfo != null && pathInfo.startsWith(SERVLET_PATH)) { - pathInfo = pathInfo.substring(SERVLET_PATH.length()); - } - - return pathInfo; - } - - /** - * @see javax.servlet.ServletRequestWrapper#setAttribute(java.lang.String, - * java.lang.Object) - */ - @Override - public void setAttribute(String name, Object value) { - Object oldValue = getAttribute(name); - - super.setAttribute(name, value); - - StartupServletContextListener listener = servletContext.getListener(); - - if (oldValue == null) { - listener.attributeAdded(new ServletRequestAttributeEvent( - servletContext, this, name, value)); - } else if (!ObjectUtils.equals(oldValue, value)) { - listener.attributeReplaced(new ServletRequestAttributeEvent( - servletContext, this, name, value)); - } - } - - /** - * @see javax.servlet.ServletRequestWrapper#removeAttribute(java.lang.String) - */ - @Override - public void removeAttribute(String name) { - Object value = getAttribute(name); - - super.removeAttribute(name); - - StartupServletContextListener listener = servletContext.getListener(); - listener.attributeRemoved(new ServletRequestAttributeEvent( - servletContext, this, name, value)); - } - - /** - * @see javax.servlet.http.HttpServletRequestWrapper#getSession() - */ - @Override - public HttpSession getSession() { - HttpSession session = super.getSession(); - - if (!(session instanceof PluginServletSession)) { - session = new PluginServletSession(servletContext, session); - } - - return session; - } - - /** - * @see javax.servlet.http.HttpServletRequestWrapper#getSession(boolean) - */ - @Override - public HttpSession getSession(boolean create) { - HttpSession session = super.getSession(create); - - if (!(session instanceof PluginServletSession)) { - session = new PluginServletSession(servletContext, session); - } - - return session; - } -} \ No newline at end of file + public static final String PLUGIN_PREFIX = "/plugin"; + + public static final String SERVLET_PATH = "/pivot4j/faces"; + + private PluginServletContext servletContext; + + /** + * @param servletContext + * @param request + */ + public PluginServletRequest(PluginServletContext servletContext, + HttpServletRequest request) { + super(request); + + this.servletContext = servletContext; + } + + /** + * @return the servletContext + */ + public PluginServletContext getServletContext() { + return servletContext; + } + + public void initialize() { + StartupServletContextListener listener = servletContext.getListener(); + listener.requestInitialized(new ServletRequestEvent(servletContext, + this)); + } + + public void destroy() { + StartupServletContextListener listener = servletContext.getListener(); + listener.requestDestroyed(new ServletRequestEvent(servletContext, this)); + } + + /** + * @see javax.servlet.http.HttpServletRequestWrapper#getServletPath() + */ + @Override + public String getServletPath() { + return PLUGIN_PREFIX + SERVLET_PATH; + } + + /** + * @see javax.servlet.http.HttpServletRequestWrapper#getPathInfo() + */ + @Override + public String getPathInfo() { + String pathInfo = super.getPathInfo(); + + if (pathInfo != null && pathInfo.startsWith(SERVLET_PATH)) { + pathInfo = pathInfo.substring(SERVLET_PATH.length()); + } + + return pathInfo; + } + + /** + * @see javax.servlet.ServletRequestWrapper#setAttribute(java.lang.String, + * java.lang.Object) + */ + @Override + public void setAttribute(String name, Object value) { + Object oldValue = getAttribute(name); + + super.setAttribute(name, value); + + StartupServletContextListener listener = servletContext.getListener(); + + if (oldValue == null) { + listener.attributeAdded(new ServletRequestAttributeEvent( + servletContext, this, name, value)); + } else if (!ObjectUtils.equals(oldValue, value)) { + listener.attributeReplaced(new ServletRequestAttributeEvent( + servletContext, this, name, value)); + } + } + + /** + * @see + * javax.servlet.ServletRequestWrapper#removeAttribute(java.lang.String) + */ + @Override + public void removeAttribute(String name) { + Object value = getAttribute(name); + + super.removeAttribute(name); + + StartupServletContextListener listener = servletContext.getListener(); + listener.attributeRemoved(new ServletRequestAttributeEvent( + servletContext, this, name, value)); + } + + /** + * @see javax.servlet.http.HttpServletRequestWrapper#getSession() + */ + @Override + public HttpSession getSession() { + HttpSession session = super.getSession(); + + if (!(session instanceof PluginServletSession)) { + session = new PluginServletSession(servletContext, session); + } + + return session; + } + + /** + * @see javax.servlet.http.HttpServletRequestWrapper#getSession(boolean) + */ + @Override + public HttpSession getSession(boolean create) { + HttpSession session = super.getSession(create); + + if (!(session instanceof PluginServletSession)) { + session = new PluginServletSession(servletContext, session); + } + + return session; + } +} diff --git a/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/servlet/PluginServletSession.java b/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/servlet/PluginServletSession.java index 75b6a7c9..a0a76584 100644 --- a/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/servlet/PluginServletSession.java +++ b/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/servlet/PluginServletSession.java @@ -20,247 +20,238 @@ @SuppressWarnings("deprecation") public class PluginServletSession implements HttpSession { - private HttpSession wrappedSession; - - private PluginServletContext servletContext; - - /** - * @param servletContext - * @param session - */ - public PluginServletSession(PluginServletContext servletContext, - HttpSession session) { - this.servletContext = servletContext; - this.wrappedSession = session; - - IPentahoSession pentahoSession = (IPentahoSession) session - .getAttribute(PentahoSystem.PENTAHO_SESSION_KEY); - - if (!(pentahoSession instanceof PentahoSessionProxy)) { - if (pentahoSession == null) { - pentahoSession = PentahoSessionHolder.getSession(); - } - - IPentahoSession proxy = (IPentahoSession) Proxy.newProxyInstance( - getClass().getClassLoader(), - new Class[] { PentahoSessionProxy.class }, - new InvocationHandlerImpl(pentahoSession)); - - session.setAttribute(PentahoSystem.PENTAHO_SESSION_KEY, proxy); - - servletContext.getListener().sessionCreated( - new HttpSessionEvent(this)); - } - } - - /** - * @return the servletContext - * @see javax.servlet.http.HttpSession#getServletContext() - */ - public PluginServletContext getServletContext() { - return servletContext; - } - - /** - * @return the wrappedSession - */ - protected HttpSession getWrappedSession() { - return wrappedSession; - } - - /** - * @return - * @see javax.servlet.http.HttpSession#getCreationTime() - */ - public long getCreationTime() { - return wrappedSession.getCreationTime(); - } - - /** - * @return - * @see javax.servlet.http.HttpSession#getId() - */ - public String getId() { - return wrappedSession.getId(); - } - - /** - * @return - * @see javax.servlet.http.HttpSession#getLastAccessedTime() - */ - public long getLastAccessedTime() { - return wrappedSession.getLastAccessedTime(); - } - - /** - * @param interval - * @see javax.servlet.http.HttpSession#setMaxInactiveInterval(int) - */ - public void setMaxInactiveInterval(int interval) { - wrappedSession.setMaxInactiveInterval(interval); - } - - /** - * @return - * @see javax.servlet.http.HttpSession#getMaxInactiveInterval() - */ - public int getMaxInactiveInterval() { - return wrappedSession.getMaxInactiveInterval(); - } - - /** - * @return - * @deprecated - * @see javax.servlet.http.HttpSession#getSessionContext() - */ - public HttpSessionContext getSessionContext() { - return wrappedSession.getSessionContext(); - } - - /** - * @param name - * @return - * @see javax.servlet.http.HttpSession#getAttribute(java.lang.String) - */ - public Object getAttribute(String name) { - return wrappedSession.getAttribute(name); - } - - /** - * @param name - * @return - * @deprecated - * @see javax.servlet.http.HttpSession#getValue(java.lang.String) - */ - public Object getValue(String name) { - return wrappedSession.getValue(name); - } - - /** - * @return - * @see javax.servlet.http.HttpSession#getAttributeNames() - */ - public Enumeration getAttributeNames() { - return wrappedSession.getAttributeNames(); - } - - /** - * @return - * @deprecated - * @see javax.servlet.http.HttpSession#getValueNames() - */ - public String[] getValueNames() { - return wrappedSession.getValueNames(); - } - - /** - * @param name - * @param value - * @see javax.servlet.http.HttpSession#setAttribute(java.lang.String, - * java.lang.Object) - */ - public void setAttribute(String name, Object value) { - wrappedSession.setAttribute(name, value); - Object oldValue = getAttribute(name); - - wrappedSession.setAttribute(name, value); - - StartupServletContextListener listener = getServletContext() - .getListener(); - if (oldValue == null) { - listener.attributeAdded(new HttpSessionBindingEvent(this, name, - value)); - } else if (!ObjectUtils.equals(oldValue, value)) { - listener.attributeReplaced(new HttpSessionBindingEvent(this, name, - value)); - } - } - - /** - * @param name - * @param value - * @deprecated - * @see javax.servlet.http.HttpSession#putValue(java.lang.String, - * java.lang.Object) - */ - public void putValue(String name, Object value) { - wrappedSession.putValue(name, value); - } - - /** - * @param name - * @see javax.servlet.http.HttpSession#removeAttribute(java.lang.String) - */ - public void removeAttribute(String name) { - Object value = getAttribute(name); - - wrappedSession.removeAttribute(name); - - StartupServletContextListener listener = getServletContext() - .getListener(); - listener.attributeRemoved(new HttpSessionBindingEvent(this, name, value)); - } - - /** - * @param name - * @deprecated - * @see javax.servlet.http.HttpSession#removeValue(java.lang.String) - */ - public void removeValue(String name) { - wrappedSession.removeValue(name); - } - - /** - * - * @see javax.servlet.http.HttpSession#invalidate() - */ - public void invalidate() { - wrappedSession.invalidate(); - } - - /** - * @return - * @see javax.servlet.http.HttpSession#isNew() - */ - public boolean isNew() { - return wrappedSession.isNew(); - } - - private interface PentahoSessionProxy extends IPentahoSession { - } - - private final class InvocationHandlerImpl implements InvocationHandler { - - private IPentahoSession session; - - private InvocationHandlerImpl(IPentahoSession session) { - this.session = session; - } - - /** - * @throws InvocationTargetException - * @throws IllegalAccessException - * @throws - * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, - * java.lang.reflect.Method, java.lang.Object[]) - */ - @Override - public Object invoke(Object proxy, Method method, Object[] args) - throws IllegalAccessException, InvocationTargetException { - Object result = method.invoke(session, args); - - if (method.getName().equals("destroy")) { - servletContext.getListener().sessionDestroyed( - new HttpSessionEvent(wrappedSession)); - - Enumeration names = getAttributeNames(); - - while (names.hasMoreElements()) { - removeAttribute((String) names.nextElement()); - } - } - - return result; - } - } + private HttpSession wrappedSession; + + private PluginServletContext servletContext; + + /** + * @param servletContext + * @param session + */ + public PluginServletSession(PluginServletContext servletContext, + HttpSession session) { + this.servletContext = servletContext; + this.wrappedSession = session; + + IPentahoSession pentahoSession = (IPentahoSession) session + .getAttribute(PentahoSystem.PENTAHO_SESSION_KEY); + + if (!(pentahoSession instanceof PentahoSessionProxy)) { + if (pentahoSession == null) { + pentahoSession = PentahoSessionHolder.getSession(); + } + + IPentahoSession proxy = (IPentahoSession) Proxy.newProxyInstance( + getClass().getClassLoader(), + new Class[]{PentahoSessionProxy.class}, + new InvocationHandlerImpl(pentahoSession)); + + session.setAttribute(PentahoSystem.PENTAHO_SESSION_KEY, proxy); + + servletContext.getListener().sessionCreated( + new HttpSessionEvent(this)); + } + } + + /** + * @return the servletContext + * @see javax.servlet.http.HttpSession#getServletContext() + */ + public PluginServletContext getServletContext() { + return servletContext; + } + + /** + * @return the wrappedSession + */ + protected HttpSession getWrappedSession() { + return wrappedSession; + } + + /** + * @return @see javax.servlet.http.HttpSession#getCreationTime() + */ + public long getCreationTime() { + return wrappedSession.getCreationTime(); + } + + /** + * @return @see javax.servlet.http.HttpSession#getId() + */ + public String getId() { + return wrappedSession.getId(); + } + + /** + * @return @see javax.servlet.http.HttpSession#getLastAccessedTime() + */ + public long getLastAccessedTime() { + return wrappedSession.getLastAccessedTime(); + } + + /** + * @param interval + * @see javax.servlet.http.HttpSession#setMaxInactiveInterval(int) + */ + public void setMaxInactiveInterval(int interval) { + wrappedSession.setMaxInactiveInterval(interval); + } + + /** + * @return @see javax.servlet.http.HttpSession#getMaxInactiveInterval() + */ + public int getMaxInactiveInterval() { + return wrappedSession.getMaxInactiveInterval(); + } + + /** + * @return @deprecated @see + * javax.servlet.http.HttpSession#getSessionContext() + */ + public HttpSessionContext getSessionContext() { + return wrappedSession.getSessionContext(); + } + + /** + * @param name + * @return + * @see javax.servlet.http.HttpSession#getAttribute(java.lang.String) + */ + public Object getAttribute(String name) { + return wrappedSession.getAttribute(name); + } + + /** + * @param name + * @return + * @deprecated + * @see javax.servlet.http.HttpSession#getValue(java.lang.String) + */ + public Object getValue(String name) { + return wrappedSession.getValue(name); + } + + /** + * @return @see javax.servlet.http.HttpSession#getAttributeNames() + */ + public Enumeration getAttributeNames() { + return wrappedSession.getAttributeNames(); + } + + /** + * @return @deprecated @see javax.servlet.http.HttpSession#getValueNames() + */ + public String[] getValueNames() { + return wrappedSession.getValueNames(); + } + + /** + * @param name + * @param value + * @see javax.servlet.http.HttpSession#setAttribute(java.lang.String, + * java.lang.Object) + */ + public void setAttribute(String name, Object value) { + wrappedSession.setAttribute(name, value); + Object oldValue = getAttribute(name); + + wrappedSession.setAttribute(name, value); + + StartupServletContextListener listener = getServletContext() + .getListener(); + if (oldValue == null) { + listener.attributeAdded(new HttpSessionBindingEvent(this, name, + value)); + } else if (!ObjectUtils.equals(oldValue, value)) { + listener.attributeReplaced(new HttpSessionBindingEvent(this, name, + value)); + } + } + + /** + * @param name + * @param value + * @deprecated + * @see javax.servlet.http.HttpSession#putValue(java.lang.String, + * java.lang.Object) + */ + public void putValue(String name, Object value) { + wrappedSession.putValue(name, value); + } + + /** + * @param name + * @see javax.servlet.http.HttpSession#removeAttribute(java.lang.String) + */ + public void removeAttribute(String name) { + Object value = getAttribute(name); + + wrappedSession.removeAttribute(name); + + StartupServletContextListener listener = getServletContext() + .getListener(); + listener.attributeRemoved(new HttpSessionBindingEvent(this, name, value)); + } + + /** + * @param name + * @deprecated + * @see javax.servlet.http.HttpSession#removeValue(java.lang.String) + */ + public void removeValue(String name) { + wrappedSession.removeValue(name); + } + + /** + * + * @see javax.servlet.http.HttpSession#invalidate() + */ + public void invalidate() { + wrappedSession.invalidate(); + } + + /** + * @return @see javax.servlet.http.HttpSession#isNew() + */ + public boolean isNew() { + return wrappedSession.isNew(); + } + + private interface PentahoSessionProxy extends IPentahoSession { + } + + private final class InvocationHandlerImpl implements InvocationHandler { + + private IPentahoSession session; + + private InvocationHandlerImpl(IPentahoSession session) { + this.session = session; + } + + /** + * @throws InvocationTargetException + * @throws IllegalAccessException + * @throws + * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, + * java.lang.reflect.Method, java.lang.Object[]) + */ + @Override + public Object invoke(Object proxy, Method method, Object[] args) + throws IllegalAccessException, InvocationTargetException { + Object result = method.invoke(session, args); + + if (method.getName().equals("destroy")) { + servletContext.getListener().sessionDestroyed( + new HttpSessionEvent(wrappedSession)); + + Enumeration names = getAttributeNames(); + + while (names.hasMoreElements()) { + removeAttribute((String) names.nextElement()); + } + } + + return result; + } + } } diff --git a/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/ui/MigrationHandler.java b/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/ui/MigrationHandler.java index da637d41..2046c83b 100644 --- a/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/ui/MigrationHandler.java +++ b/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/ui/MigrationHandler.java @@ -39,7 +39,7 @@ import org.pivot4j.mdx.MdxStatement; import org.pivot4j.mdx.impl.MdxParserImpl; import org.pivot4j.ui.table.TableRenderer; -import org.primefaces.context.RequestContext; +import org.primefaces.PrimeFaces; import org.primefaces.model.DefaultTreeNode; import org.primefaces.model.TreeNode; import org.slf4j.Logger; @@ -49,550 +49,544 @@ @ViewScoped public class MigrationHandler { - private Logger log = LoggerFactory.getLogger(getClass()); + private Logger log = LoggerFactory.getLogger(getClass()); - @ManagedProperty(value = "#{dataSourceManager}") - private DataSourceManager dataSourceManager; + @ManagedProperty(value = "#{dataSourceManager}") + private DataSourceManager dataSourceManager; - @ManagedProperty(value = "#{settings}") - private Settings settings; + @ManagedProperty(value = "#{settings}") + private Settings settings; - @ManagedProperty(value = "#{reportRepository}") - private ReportRepository repository; + @ManagedProperty(value = "#{reportRepository}") + private ReportRepository repository; - @ManagedProperty(value = "#{viewStateHolder}") - private ViewStateHolder viewStateHolder; + @ManagedProperty(value = "#{viewStateHolder}") + private ViewStateHolder viewStateHolder; - private TreeNode rootNode; + private TreeNode rootNode; - private TreeNode selection; + private TreeNode selection; - private String viewId; + private String viewId; - private List convertedFiles = new LinkedList(); + private List convertedFiles = new LinkedList(); - private Entry selectedFile; + private Entry selectedFile; - private boolean migrationDone = false; + private boolean migrationDone = false; - private RepositoryFileFilter fileFilter = new MigrationTargetFilter(); + private RepositoryFileFilter fileFilter = new MigrationTargetFilter(); - public boolean isOkButtonEnabled() { - if (migrationDone) { - return selectedFile != null && selectedFile.getError() == null; - } else { - return selection != null; - } - } + public boolean isOkButtonEnabled() { + if (migrationDone) { + return selectedFile != null && selectedFile.getError() == null; + } else { + return selection != null; + } + } - public String proceed() { - FacesContext context = FacesContext.getCurrentInstance(); - ResourceBundle bundle = context.getApplication().getResourceBundle( - context, "plugin_msg"); + public String proceed() { + FacesContext context = FacesContext.getCurrentInstance(); + ResourceBundle bundle = context.getApplication().getResourceBundle( + context, "plugin_msg"); - String navigation = null; + String navigation = null; - try { - if (migrationDone) { - navigation = open(selectedFile.getResult(), false); - } else { - convertedFiles.clear(); + try { + if (migrationDone) { + navigation = open(selectedFile.getResult(), false); + } else { + convertedFiles.clear(); - ReportFile target; + ReportFile target; - if (selection instanceof RepositoryNode) { - target = ((RepositoryNode) selection).getObject(); - } else { - target = repository.getRoot(); - } + if (selection instanceof RepositoryNode) { + target = ((RepositoryNode) selection).getObject(); + } else { + target = repository.getRoot(); + } - if (target.isDirectory()) { - convertFiles(target); - } else { - navigation = open(target, true); - } + if (target.isDirectory()) { + convertFiles(target); + } else { + navigation = open(target, true); + } - RequestContext.getCurrentInstance().execute( - "if (parent) parent.mantle_refreshRepository()"); + PrimeFaces.current().executeScript( + "if (parent) parent.mantle_refreshRepository()"); - this.migrationDone = true; - } - } catch (Exception e) { - String title = bundle.getString("title.migrate.error"); - String message = bundle.getString("message.migrate.error") + e; + this.migrationDone = true; + } + } catch (Exception e) { + String title = bundle.getString("title.migrate.error"); + String message = bundle.getString("message.migrate.error") + e; - context.addMessage(null, new FacesMessage( - FacesMessage.SEVERITY_ERROR, title, message)); + context.addMessage(null, new FacesMessage( + FacesMessage.SEVERITY_ERROR, title, message)); - if (log.isErrorEnabled()) { - log.error(message, e); - } - } + if (log.isErrorEnabled()) { + log.error(message, e); + } + } - return navigation; - } + return navigation; + } - public String getSummary() { - FacesContext context = FacesContext.getCurrentInstance(); - ResourceBundle bundle = context.getApplication().getResourceBundle( - context, "plugin_msg"); + public String getSummary() { + FacesContext context = FacesContext.getCurrentInstance(); + ResourceBundle bundle = context.getApplication().getResourceBundle( + context, "plugin_msg"); - int count = 0; + int count = 0; - for (Entry entry : convertedFiles) { - if (entry.getError() == null) { - count++; - } - } - - String message = String.format( - bundle.getString("message.migrate.success"), count); - - return message; - } - - /** - * @param file - * @param convert - * @return - * @throws IOException - * @throws ConfigurationException - * @throws DataSourceNotFoundException - * @throws InvalidConnectionInfoException - */ - public String open(ReportFile file, boolean convert) throws IOException, - ConfigurationException, DataSourceNotFoundException, - InvalidConnectionInfoException { - FacesContext context = FacesContext.getCurrentInstance(); - - ViewState state; - - if (convert) { - state = convertFile(file); - state.setDirty(true); - } else { - state = new ViewState(viewId, file.getName()); - state.setFile(file); - - ReportContent content = repository.getReportContent(file); - content.read(state, dataSourceManager, settings.getConfiguration()); - } - - state.getModel().initialize(); - - viewStateHolder.registerState(state); - - Flash flash = context.getExternalContext().getFlash(); - - flash.put("connectionInfo", state.getConnectionInfo()); - flash.put("viewId", state.getId()); - - StringBuilder builder = new StringBuilder(); - builder.append("view"); - builder.append("?faces-redirect=true"); - builder.append("&"); - builder.append(settings.getViewParameterName()); - builder.append("="); - builder.append(state.getId()); - - return builder.toString(); - } - - /** - * @param parent - * @throws IOException - * @throws ConfigurationException - */ - protected void convertFiles(ReportFile parent) throws IOException, - ConfigurationException { - List files = repository.getFiles(parent, fileFilter); - - for (ReportFile file : files) { - if (file.isDirectory()) { - convertFiles(file); - } else { - String error = null; - - ReportFile result = null; - - FacesContext context = FacesContext.getCurrentInstance(); - ResourceBundle bundle = context.getApplication() - .getResourceBundle(context, "plugin_msg"); - - try { - ViewState state = convertFile(file); - - String name = file.getName().substring( - 0, - file.getName().length() - - file.getExtension().length()) - + "pivot4j"; - - result = repository.createFile(parent, name, - new ReportContent(state)); - } catch (InvalidConnectionInfoException e) { - error = bundle - .getString("message.migrate.error.dataSource"); - } catch (Exception e) { - error = bundle.getString("message.migrate.error") + e; - - if (log.isErrorEnabled()) { - log.error(error, e); - } - } - - convertedFiles.add(new Entry(file, result, error)); - } - } - } - - /** - * @param file - * @return - * @throws InvalidConnectionInfoException - * @throws ConfigurationException - * @throws IOException - */ - protected ViewState convertFile(ReportFile file) - throws InvalidConnectionInfoException, ConfigurationException, - IOException { - if (log.isDebugEnabled()) { - log.debug("Migrating JPivot report : " + file); - } - - InputStream in = null; - - try { - in = repository.readContent(file); - - XMLConfiguration config = new XMLConfiguration(); - config.setRootElementName("action-sequence"); - config.setDelimiterParsingDisabled(true); - config.load(in); - - return convertFile(config); - } finally { - IOUtils.closeQuietly(in); - } - } - - /** - * @param config - * @return - * @throws InvalidConnectionInfoException - */ - protected ViewState convertFile(HierarchicalConfiguration config) - throws InvalidConnectionInfoException { - HierarchicalConfiguration report = config - .configurationAt("actions.action-definition.component-definition"); - - String title = report.getString("title"); - String query = report.getString("query"); - String cube = report.getString("cube"); - String catalog = report.getString("model"); - - if (log.isDebugEnabled()) { - log.debug(" - title : " + title); - log.debug(" - query : " + query); - log.debug(" - cube : " + cube); - log.debug(" - catalog : " + catalog); - } - - if (cube == null) { - // NOTE : Pentaho JPivot plugin seems to have a bug with storing - // catalog and cube names when more than one analysis data sources - // are registered. So we need to check for such an error and try to - // guess the correct names. - - String originalCubeName = cube; - String originalCatalogName = catalog; - - if (log.isWarnEnabled()) { - log.warn("Cube name is not specified. Trying to guess the correct cube and catalog names."); - } - - MdxParser parser = new MdxParserImpl(); - MdxStatement statement = parser.parse(query); - - cube = statement.getCube().getNames().get(0).getUnquotedName(); - - if (log.isInfoEnabled()) { - log.info("Cube name specified in MDX query : " + cube); - } - - List cubes = dataSourceManager.getCubes(catalog); - - boolean found = false; - - for (CubeInfo cubeInfo : cubes) { - found = cubeInfo.getName().equalsIgnoreCase(cube); - if (found) { - cube = cubeInfo.getName(); - break; - } - } - - if (!found) { - throw new InvalidConnectionInfoException(originalCubeName, - originalCatalogName); - } - } - - ConnectionInfo connectionInfo = new ConnectionInfo(catalog, cube); - - OlapDataSource dataSource = dataSourceManager - .getDataSource(connectionInfo); - - PivotModel model = new PivotModelImpl(dataSource); - model.setMdx(query); - - TableRenderer renderer = new DefaultTableRenderer(); - - // NOTE : Pentaho JPivot plugin does not preserve rendering states in - // saved reports, despite they contain related - // tags for such properties(i.e. ). - - ViewState state = viewStateHolder - .createNewState(connectionInfo, viewId); - - state.setName(title); - state.setConnectionInfo(connectionInfo); - state.setModel(model); - state.setRendererState(renderer.saveState()); - - return state; - } - - /** - * @return the viewId - */ - public String getViewId() { - return viewId; - } - - /** - * @param viewId - * the viewId to set - */ - public void setViewId(String viewId) { - this.viewId = viewId; - } - - /** - * @return the repository - */ - public ReportRepository getRepository() { - return repository; - } - - /** - * @param repository - * the repository to set - */ - public void setRepository(ReportRepository repository) { - this.repository = repository; - } - - /** - * @return the dataSourceManager - */ - public DataSourceManager getDataSourceManager() { - return dataSourceManager; - } - - /** - * @param dataSourceManager - * the dataSourceManager to set - */ - public void setDataSourceManager(DataSourceManager dataSourceManager) { - this.dataSourceManager = dataSourceManager; - } - - /** - * @return the settings - */ - public Settings getSettings() { - return settings; - } - - /** - * @param settings - * the settings to set - */ - public void setSettings(Settings settings) { - this.settings = settings; - } - - /** - * @return the viewStateHolder - */ - public ViewStateHolder getViewStateHolder() { - return viewStateHolder; - } - - /** - * @param viewStateHolder - * the viewStateHolder to set - */ - public void setViewStateHolder(ViewStateHolder viewStateHolder) { - this.viewStateHolder = viewStateHolder; - } - - /** - * @return the rootNode - */ - public TreeNode getRootNode() { - if (rootNode == null) { - this.rootNode = new DefaultTreeNode(); - rootNode.setExpanded(true); - - RepositoryNode node; - - try { - node = new RepositoryNode(repository.getRoot(), repository); - } catch (IOException e) { - throw new FacesException(e); - } - - node.setExpanded(true); - node.setFilter(fileFilter); - - rootNode.getChildren().add(node); - } - - return rootNode; - } - - protected RepositoryNode getRepositoryRootNode() { - return (RepositoryNode) getRootNode().getChildren().get(0); - } - - public TreeNode getSelection() { - return selection; - } - - public void setSelection(TreeNode selection) { - this.selection = selection; - } - - /** - * @return the convertedFiles - */ - public List getConvertedFiles() { - return convertedFiles; - } - - /** - * @return the selectedFile - */ - public Entry getSelectedFile() { - return selectedFile; - } - - /** - * @param selectedFile - * the selectedFile to set - */ - public void setSelectedFile(Entry selectedFile) { - this.selectedFile = selectedFile; - } - - /** - * @return the migrationDone - */ - public boolean isMigrationDone() { - return migrationDone; - } - - static class MigrationTargetFilter implements RepositoryFileFilter, - Serializable { - - private static final long serialVersionUID = 4427077075329175626L; - - /** - * @see org.pivot4j.analytics.repository.RepositoryFileFilter#accept(org.pivot4j.analytics.repository.ReportFile) - */ - @Override - public boolean accept(ReportFile file) { - if (file.isDirectory()) { - return !file.getPath().startsWith(ReportFile.SEPARATOR + "etc"); - } else { - return "xaction".equalsIgnoreCase(file.getExtension()) - || "xjpivot".equalsIgnoreCase(file.getExtension()); - } - } - } - - static class InvalidConnectionInfoException extends Exception { - - private static final long serialVersionUID = 8066830074992740616L; - - private String cube; - - private String catalog; - - /** - * @param cube - * @param catalog - */ - private InvalidConnectionInfoException(String cube, String catalog) { - this.cube = cube; - this.catalog = catalog; - } - - /** - * @return the cube - */ - public String getCube() { - return cube; - } - - /** - * @return the catalog - */ - public String getCatalog() { - return catalog; - } - } - - public static class Entry { - - private ReportFile file; - - private ReportFile result; - - private String error; - - /** - * @param file - * @param result - * @param error - */ - private Entry(ReportFile file, ReportFile result, String error) { - this.file = file; - this.error = error; - this.result = result; - } - - /** - * @return the file - */ - public ReportFile getFile() { - return file; - } - - /** - * @return the result - */ - public ReportFile getResult() { - return result; - } - - /** - * @return the error - */ - public String getError() { - return error; - } - } + for (Entry entry : convertedFiles) { + if (entry.getError() == null) { + count++; + } + } + + String message = String.format( + bundle.getString("message.migrate.success"), count); + + return message; + } + + /** + * @param file + * @param convert + * @return + * @throws IOException + * @throws ConfigurationException + * @throws DataSourceNotFoundException + * @throws InvalidConnectionInfoException + */ + public String open(ReportFile file, boolean convert) throws IOException, + ConfigurationException, DataSourceNotFoundException, + InvalidConnectionInfoException { + FacesContext context = FacesContext.getCurrentInstance(); + + ViewState state; + + if (convert) { + state = convertFile(file); + state.setDirty(true); + } else { + state = new ViewState(viewId, file.getName()); + state.setFile(file); + + ReportContent content = repository.getReportContent(file); + content.read(state, dataSourceManager, settings.getConfiguration()); + } + + state.getModel().initialize(); + + viewStateHolder.registerState(state); + + Flash flash = context.getExternalContext().getFlash(); + + flash.put("connectionInfo", state.getConnectionInfo()); + flash.put("viewId", state.getId()); + + StringBuilder builder = new StringBuilder(); + builder.append("view"); + builder.append("?faces-redirect=true"); + builder.append("&"); + builder.append(settings.getViewParameterName()); + builder.append("="); + builder.append(state.getId()); + + return builder.toString(); + } + + /** + * @param parent + * @throws IOException + * @throws ConfigurationException + */ + protected void convertFiles(ReportFile parent) throws IOException, + ConfigurationException { + List files = repository.getFiles(parent, fileFilter); + + for (ReportFile file : files) { + if (file.isDirectory()) { + convertFiles(file); + } else { + String error = null; + + ReportFile result = null; + + FacesContext context = FacesContext.getCurrentInstance(); + ResourceBundle bundle = context.getApplication() + .getResourceBundle(context, "plugin_msg"); + + try { + ViewState state = convertFile(file); + + String name = file.getName().substring( + 0, + file.getName().length() + - file.getExtension().length()) + + "pivot4j"; + + result = repository.createFile(parent, name, + new ReportContent(state)); + } catch (InvalidConnectionInfoException e) { + error = bundle + .getString("message.migrate.error.dataSource"); + } catch (Exception e) { + error = bundle.getString("message.migrate.error") + e; + + if (log.isErrorEnabled()) { + log.error(error, e); + } + } + + convertedFiles.add(new Entry(file, result, error)); + } + } + } + + /** + * @param file + * @return + * @throws InvalidConnectionInfoException + * @throws ConfigurationException + * @throws IOException + */ + protected ViewState convertFile(ReportFile file) + throws InvalidConnectionInfoException, ConfigurationException, + IOException { + if (log.isDebugEnabled()) { + log.debug("Migrating JPivot report : " + file); + } + + InputStream in = null; + + try { + in = repository.readContent(file); + + XMLConfiguration config = new XMLConfiguration(); + config.setRootElementName("action-sequence"); + config.setDelimiterParsingDisabled(true); + config.load(in); + + return convertFile(config); + } finally { + IOUtils.closeQuietly(in); + } + } + + /** + * @param config + * @return + * @throws InvalidConnectionInfoException + */ + protected ViewState convertFile(HierarchicalConfiguration config) + throws InvalidConnectionInfoException { + HierarchicalConfiguration report = config + .configurationAt("actions.action-definition.component-definition"); + + String title = report.getString("title"); + String query = report.getString("query"); + String cube = report.getString("cube"); + String catalog = report.getString("model"); + + if (log.isDebugEnabled()) { + log.debug(" - title : " + title); + log.debug(" - query : " + query); + log.debug(" - cube : " + cube); + log.debug(" - catalog : " + catalog); + } + + if (cube == null) { + // NOTE : Pentaho JPivot plugin seems to have a bug with storing + // catalog and cube names when more than one analysis data sources + // are registered. So we need to check for such an error and try to + // guess the correct names. + + String originalCubeName = cube; + String originalCatalogName = catalog; + + if (log.isWarnEnabled()) { + log.warn("Cube name is not specified. Trying to guess the correct cube and catalog names."); + } + + MdxParser parser = new MdxParserImpl(); + MdxStatement statement = parser.parse(query); + + cube = statement.getCube().getNames().get(0).getUnquotedName(); + + if (log.isInfoEnabled()) { + log.info("Cube name specified in MDX query : " + cube); + } + + List cubes = dataSourceManager.getCubes(catalog); + + boolean found = false; + + for (CubeInfo cubeInfo : cubes) { + found = cubeInfo.getName().equalsIgnoreCase(cube); + if (found) { + cube = cubeInfo.getName(); + break; + } + } + + if (!found) { + throw new InvalidConnectionInfoException(originalCubeName, + originalCatalogName); + } + } + + ConnectionInfo connectionInfo = new ConnectionInfo(catalog, cube); + + OlapDataSource dataSource = dataSourceManager + .getDataSource(connectionInfo); + + PivotModel model = new PivotModelImpl(dataSource); + model.setMdx(query); + + TableRenderer renderer = new DefaultTableRenderer(); + + // NOTE : Pentaho JPivot plugin does not preserve rendering states in + // saved reports, despite they contain related + // tags for such properties(i.e. ). + ViewState state = viewStateHolder + .createNewState(connectionInfo, viewId); + + state.setName(title); + state.setConnectionInfo(connectionInfo); + state.setModel(model); + state.setRendererState(renderer.saveState()); + + return state; + } + + /** + * @return the viewId + */ + public String getViewId() { + return viewId; + } + + /** + * @param viewId the viewId to set + */ + public void setViewId(String viewId) { + this.viewId = viewId; + } + + /** + * @return the repository + */ + public ReportRepository getRepository() { + return repository; + } + + /** + * @param repository the repository to set + */ + public void setRepository(ReportRepository repository) { + this.repository = repository; + } + + /** + * @return the dataSourceManager + */ + public DataSourceManager getDataSourceManager() { + return dataSourceManager; + } + + /** + * @param dataSourceManager the dataSourceManager to set + */ + public void setDataSourceManager(DataSourceManager dataSourceManager) { + this.dataSourceManager = dataSourceManager; + } + + /** + * @return the settings + */ + public Settings getSettings() { + return settings; + } + + /** + * @param settings the settings to set + */ + public void setSettings(Settings settings) { + this.settings = settings; + } + + /** + * @return the viewStateHolder + */ + public ViewStateHolder getViewStateHolder() { + return viewStateHolder; + } + + /** + * @param viewStateHolder the viewStateHolder to set + */ + public void setViewStateHolder(ViewStateHolder viewStateHolder) { + this.viewStateHolder = viewStateHolder; + } + + /** + * @return the rootNode + */ + public TreeNode getRootNode() { + if (rootNode == null) { + this.rootNode = new DefaultTreeNode(); + rootNode.setExpanded(true); + + RepositoryNode node; + + try { + node = new RepositoryNode(repository.getRoot(), repository); + } catch (IOException e) { + throw new FacesException(e); + } + + node.setExpanded(true); + node.setFilter(fileFilter); + + rootNode.getChildren().add(node); + } + + return rootNode; + } + + protected RepositoryNode getRepositoryRootNode() { + return (RepositoryNode) getRootNode().getChildren().get(0); + } + + public TreeNode getSelection() { + return selection; + } + + public void setSelection(TreeNode selection) { + this.selection = selection; + } + + /** + * @return the convertedFiles + */ + public List getConvertedFiles() { + return convertedFiles; + } + + /** + * @return the selectedFile + */ + public Entry getSelectedFile() { + return selectedFile; + } + + /** + * @param selectedFile the selectedFile to set + */ + public void setSelectedFile(Entry selectedFile) { + this.selectedFile = selectedFile; + } + + /** + * @return the migrationDone + */ + public boolean isMigrationDone() { + return migrationDone; + } + + static class MigrationTargetFilter implements RepositoryFileFilter, + Serializable { + + private static final long serialVersionUID = 4427077075329175626L; + + /** + * @see + * org.pivot4j.analytics.repository.RepositoryFileFilter#accept(org.pivot4j.analytics.repository.ReportFile) + */ + @Override + public boolean accept(ReportFile file) { + if (file.isDirectory()) { + return !file.getPath().startsWith(ReportFile.SEPARATOR + "etc"); + } else { + return "xaction".equalsIgnoreCase(file.getExtension()) + || "xjpivot".equalsIgnoreCase(file.getExtension()); + } + } + } + + static class InvalidConnectionInfoException extends Exception { + + private static final long serialVersionUID = 8066830074992740616L; + + private String cube; + + private String catalog; + + /** + * @param cube + * @param catalog + */ + private InvalidConnectionInfoException(String cube, String catalog) { + this.cube = cube; + this.catalog = catalog; + } + + /** + * @return the cube + */ + public String getCube() { + return cube; + } + + /** + * @return the catalog + */ + public String getCatalog() { + return catalog; + } + } + + public static class Entry { + + private ReportFile file; + + private ReportFile result; + + private String error; + + /** + * @param file + * @param result + * @param error + */ + private Entry(ReportFile file, ReportFile result, String error) { + this.file = file; + this.error = error; + this.result = result; + } + + /** + * @return the file + */ + public ReportFile getFile() { + return file; + } + + /** + * @return the result + */ + public ReportFile getResult() { + return result; + } + + /** + * @return the error + */ + public String getError() { + return error; + } + } } diff --git a/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/ui/PentahoReportOpener.java b/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/ui/PentahoReportOpener.java index e5e53993..83c1e1ec 100644 --- a/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/ui/PentahoReportOpener.java +++ b/pivot4j-pentaho/src/main/java/org/pivot4j/pentaho/ui/PentahoReportOpener.java @@ -22,128 +22,130 @@ public class PentahoReportOpener extends ReportOpener { - /** - * @throws IOException - * @see org.pivot4j.analytics.ui.ReportOpener#getReportFromRequest(javax.servlet.http.HttpServletRequest) - */ - @Override - protected ReportFile getReportFromRequest(HttpServletRequest request) - throws IOException { - ReportFile file = null; - - RepositoryFile repositoryFile = (RepositoryFile) request - .getAttribute("file"); - - if (repositoryFile == null) { - file = super.getReportFromRequest(request); - } else { - file = getReportRepository().getFile(repositoryFile.getPath()); - } - - return file; - } - - /** - * @see org.pivot4j.analytics.ui.ReportOpener#createViewWithRequest(javax.servlet.http.HttpServletRequest, - * org.pivot4j.analytics.repository.ReportFile) - */ - @Override - protected ViewState createViewWithRequest(HttpServletRequest request, - ReportFile file) { - ViewState state = super.createViewWithRequest(request, file); - - PentahoReportFile pentahoFile = (PentahoReportFile) file; - - state.setName(pentahoFile.getTitle()); - state.setReadOnly(!file.canWrite()); - state.setEditable(!state.isReadOnly() - && !"false".equalsIgnoreCase(request.getParameter("editable"))); - - return state; - } - - /** - * @throws PentahoAccessControlException - * @throws IOException - * @throws ConfigurationException - */ - public void save() throws PentahoAccessControlException, IOException, - ConfigurationException { - FacesContext context = FacesContext.getCurrentInstance(); - - Map parameters = context.getExternalContext() - .getRequestParameterMap(); - String viewId = parameters.get("viewId"); - - String extension = "." + PentahoReportFile.DEFAULT_EXTENSION; - - String fileName = parameters.get("fileName"); - if (!fileName.endsWith(extension)) { - fileName += extension; - } - - String path = parameters.get("path"); - - if (path.endsWith(fileName)) { - path = path.substring(0, path.length() - fileName.length() - 1); - } - - if (!path.endsWith(RepositoryFile.SEPARATOR)) { - path += RepositoryFile.SEPARATOR; - } - - boolean overwrite = Boolean.parseBoolean(parameters.get("overwrite")); - - save(viewId, path, fileName, overwrite); - } - - /** - * @param viewId - * @param path - * @param fileName - * @param overwrite - * @throws PentahoAccessControlException - * @throws IOException - * @throws ConfigurationException - */ - public void save(String viewId, String path, String fileName, - boolean overwrite) throws PentahoAccessControlException, - IOException, ConfigurationException { - Logger logger = LoggerFactory.getLogger(getClass()); - if (logger.isInfoEnabled()) { - logger.info("Saving report content to repository :"); - logger.info(" - viewId : " + viewId); - logger.info(" - path : " + path); - logger.info(" - fileName : " + fileName); - logger.info(" - overwrite : " + overwrite); - } - - ViewState state = getViewStateHolder().getState(viewId); - - ReportContent content = new ReportContent(state); - - String filePath = path + fileName; - - PentahoReportRepository repository = (PentahoReportRepository) getReportRepository(); - - ReportFile file = repository.getFile(filePath); - - if (file == null) { - ReportFile parent = repository.getFile(path); - file = repository.createFile(parent, fileName, content, overwrite); - } else { - repository.setReportContent(file, content); - } - - FacesContext context = FacesContext.getCurrentInstance(); - ResourceBundle bundle = context.getApplication().getResourceBundle( - context, "msg"); - - String title = bundle.getString("message.save.report.title"); - String message = bundle.getString("message.saveAs.report.message") - + file.getPath(); - - context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, - title, message)); - } + /** + * @throws IOException + * @see + * org.pivot4j.analytics.ui.ReportOpener#getReportFromRequest(javax.servlet.http.HttpServletRequest) + */ + @Override + protected ReportFile getReportFromRequest(HttpServletRequest request) + throws IOException { + ReportFile file = null; + + RepositoryFile repositoryFile = (RepositoryFile) request + .getAttribute("file"); + + if (repositoryFile == null) { + file = super.getReportFromRequest(request); + } else { + file = getReportRepository().getFile(repositoryFile.getPath()); + } + + return file; + } + + /** + * @see + * org.pivot4j.analytics.ui.ReportOpener#createViewWithRequest(javax.servlet.http.HttpServletRequest, + * org.pivot4j.analytics.repository.ReportFile) + */ + @Override + protected ViewState createViewWithRequest(HttpServletRequest request, + ReportFile file) { + ViewState state = super.createViewWithRequest(request, file); + + PentahoReportFile pentahoFile = (PentahoReportFile) file; + + state.setName(pentahoFile.getTitle()); + state.setReadOnly(!file.canWrite()); + state.setEditable(!state.isReadOnly() + && !"false".equalsIgnoreCase(request.getParameter("editable"))); + + return state; + } + + /** + * @throws PentahoAccessControlException + * @throws IOException + * @throws ConfigurationException + */ + public void save() throws PentahoAccessControlException, IOException, + ConfigurationException { + FacesContext context = FacesContext.getCurrentInstance(); + + Map parameters = context.getExternalContext() + .getRequestParameterMap(); + String viewId = parameters.get("viewId"); + + String extension = "." + PentahoReportFile.DEFAULT_EXTENSION; + + String fileName = parameters.get("fileName"); + if (!fileName.endsWith(extension)) { + fileName += extension; + } + + String path = parameters.get("path"); + + if (path.endsWith(fileName)) { + path = path.substring(0, path.length() - fileName.length() - 1); + } + + if (!path.endsWith(RepositoryFile.SEPARATOR)) { + path += RepositoryFile.SEPARATOR; + } + + boolean overwrite = Boolean.parseBoolean(parameters.get("overwrite")); + + save(viewId, path, fileName, overwrite); + } + + /** + * @param viewId + * @param path + * @param fileName + * @param overwrite + * @throws PentahoAccessControlException + * @throws IOException + * @throws ConfigurationException + */ + public void save(String viewId, String path, String fileName, + boolean overwrite) throws PentahoAccessControlException, + IOException, ConfigurationException { + Logger logger = LoggerFactory.getLogger(getClass()); + if (logger.isInfoEnabled()) { + logger.info("Saving report content to repository :"); + logger.info(" - viewId : " + viewId); + logger.info(" - path : " + path); + logger.info(" - fileName : " + fileName); + logger.info(" - overwrite : " + overwrite); + } + + ViewState state = getViewStateHolder().getState(viewId); + + ReportContent content = new ReportContent(state); + + String filePath = path + fileName; + + PentahoReportRepository repository = (PentahoReportRepository) getReportRepository(); + + ReportFile file = repository.getFile(filePath); + + if (file == null) { + ReportFile parent = repository.getFile(path); + file = repository.createFile(parent, fileName, content, overwrite); + } else { + repository.setReportContent(file, content); + } + + FacesContext context = FacesContext.getCurrentInstance(); + ResourceBundle bundle = context.getApplication().getResourceBundle( + context, "msg"); + + String title = bundle.getString("message.save.report.title"); + String message = bundle.getString("message.saveAs.report.message") + + file.getPath(); + + context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, + title, message)); + } } diff --git a/pivot4j-pentaho/src/main/plugin/pivot4j-config.xml b/pivot4j-pentaho/src/main/plugin/pivot4j-config.xml index 1e21f050..c154a586 100644 --- a/pivot4j-pentaho/src/main/plugin/pivot4j-config.xml +++ b/pivot4j-pentaho/src/main/plugin/pivot4j-config.xml @@ -2,48 +2,48 @@ - - - - redmond - - - - - - - - - - + + + + redmond + + + + + + + + + + - - eclipse - + + eclipse + - - - + + + - - - - + + + + - - - - /api/repos/pivot4j/webapp + + + + /api/repos/pivot4j/webapp - - locale_override + + locale_override - - ts - + + ts + \ No newline at end of file diff --git a/pivot4j-pentaho/src/main/plugin/plugin.spring.xml b/pivot4j-pentaho/src/main/plugin/plugin.spring.xml index 2ea9ef9a..d7948e1d 100644 --- a/pivot4j-pentaho/src/main/plugin/plugin.spring.xml +++ b/pivot4j-pentaho/src/main/plugin/plugin.spring.xml @@ -1,44 +1,44 @@ - + - - - - - Production - - - true - - - server - - - false - - - false - - - org.pivot4j.pentaho.servlet.PluginResourceResolver - - - - #{'#{workbenchHandler.theme}'} - - - classpath:./pivot4j-config.xml - - - - + + + + + Production + + + true + + + server + + + false + + + false + + + org.pivot4j.pentaho.servlet.PluginResourceResolver + + + + #{'#{workbenchHandler.theme}'} + + + classpath:./pivot4j-config.xml + + + + diff --git a/pivot4j-pentaho/src/main/plugin/plugin.xml b/pivot4j-pentaho/src/main/plugin/plugin.xml index 721e30d9..0cbe57b3 100644 --- a/pivot4j-pentaho/src/main/plugin/plugin.xml +++ b/pivot4j-pentaho/src/main/plugin/plugin.xml @@ -1,46 +1,46 @@ - - - + + + - - -